Movatterモバイル変換


[0]ホーム

URL:


Theme

Clippy LintsTotal number: 795

absolute_paths📋
restrictionallow

What it does

Checks for usage of items through absolute paths, likestd::env::current_dir.

Why restrict this?

Many codebases have their own style when it comes to importing, but one that is seldom usedis using absolute pathseverywhere. This is generally considered unidiomatic, and youshould add ause statement.

The default maximum segments (2) is pretty strict, you may want to increase this inclippy.toml.

Note: One exception to this is code from macro expansion - this does not lint such cases, asusing absolute paths is the proper way of referencing items in one.

Known issues

There are currently a few cases which are not caught by this lint:

  • Macro calls. e.g.path::to::macro!()
  • Derive macros. e.g.#[derive(path::to::macro)]
  • Attribute macros. e.g.#[path::to::macro]

Example

let x = std::f64::consts::PI;

Use any of the below instead, or anything else:

use std::f64;use std::f64::consts;use std::f64::consts::PI;let x = f64::consts::PI;let x = consts::PI;let x = PI;use std::f64::consts as f64_consts;let x = f64_consts::PI;

Configuration

  • absolute-paths-allowed-crates: Which crates to allow absolute paths from

    (default:[])

  • absolute-paths-max-segments: The maximum number of segments a path can have before being linted, anything above this willbe linted.

    (default:2)

Applicability:Unspecified(?)
Added in:1.73.0
Related Issues
View Source

absurd_extreme_comparisons📋
correctnessdeny

What it does

Checks for comparisons where one side of the relation iseither the minimum or maximum value for its type and warns if it involves acase that is always true or always false. Only integer and boolean types arechecked.

Why is this bad?

An expression likemin <= x may misleadingly implythat it is possible forx to be less than the minimum. Expressions likemax < x are probably mistakes.

Known problems

Forusize the size of the current compile target willbe assumed (e.g., 64 bits on 64 bit systems). This means code that uses sucha comparison to detect target pointer width will trigger this lint. One canusemem::sizeof and compare its value or conditional compilationattributeslike#[cfg(target_pointer_width = "64")] .. instead.

Example

let vec: Vec<isize> = Vec::new();if vec.len() <= 0 {}if 100 > i32::MAX {}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

alloc_instead_of_core📋
restrictionallow

What it does

Finds items imported throughalloc when available throughcore.

Why restrict this?

Crates which haveno_std compatibility and may optionally require alloc may wish to ensure types areimported from core to ensure disablingalloc does not cause the crate to fail to compile. This lintis also useful for crates migrating to becomeno_std compatible.

Known problems

The lint is only partially aware of the required MSRV for items that were originally instd but movedtocore.

Example

use alloc::slice::from_ref;

Use instead:

use core::slice::from_ref;
Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

allow_attributes📋
restrictionallow

What it does

Checks for usage of the#[allow] attribute and suggests replacing it withthe#[expect] attribute (SeeRFC 2383)

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, ifthe expectation is unfulfilled. This can be useful to be notified when thelint is no longer triggered.

Example

#[allow(unused_mut)]fn foo() -> usize {    let mut a = Vec::new();    a.len()}

Use instead:

#[expect(unused_mut)]fn foo() -> usize {    let mut a = Vec::new();    a.len()}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.70.0
Related Issues
View Source

allow_attributes_without_reason📋
restrictionallow

What it does

Checks for attributes that allow lints without a reason.

Why restrict this?

Justifying eachallow helps readers understand the reasoning,and may allow removingallow attributes if their purpose is obsolete.

Example

#![allow(clippy::some_lint)]

Use instead:

#![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:Unspecified(?)
Added in:1.61.0
Related Issues
View Source

almost_complete_range📋
suspiciouswarn

What it does

Checks for ranges which almost include the entire range of letters from ‘a’ to ‘z’or digits from ‘0’ to ‘9’, but don’t because they’re a half open range.

Why is this bad?

This ('a'..'z') is almost certainly a typo meant to include all letters.

Example

let _ = 'a'..'z';

Use instead:

let _ = 'a'..='z';

Past names

  • almost_complete_letter_range

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.68.0
Related Issues
View Source

almost_swapped📋
correctnessdeny

What it does

Checks forfoo = bar; bar = foo sequences.

Why is this bad?

This looks like a failed attempt to swap.

Example

a = b;b = a;

If swapping is intended, useswap() instead:

std::mem::swap(&mut a, &mut b);
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

approx_constant📋
correctnessdeny

What it does

Checks for floating point literals that approximateconstants which are defined instd::f32::constsorstd::f64::consts,respectively, suggesting to use the predefined constant.

Why is this bad?

Usually, the definition in the standard library is moreprecise than what people come up with. If you find that your definition isactually more precise, pleasefile a Rustissue.

Example

let x = 3.14;let y = 1_f64 / x;

Use instead:

let x = std::f32::consts::PI;let y = std::f64::consts::FRAC_1_PI;

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

arbitrary_source_item_ordering📋
restrictionallow

What it does

Confirms that items are sorted in source files as per configuration.

Why restrict this?

Keeping a consistent ordering throughout the codebase helps with workingas a team, and possibly improves maintainability of the codebase. Theidea is that by defining a consistent and enforceable rule for howsource files are structured, less time will be wasted during reviews ona topic that is (under most circumstances) not relevant to the logicimplemented in the code. Sometimes this will be referred to as“bikeshedding”.

The content of items with a representation clause attribute, such as#[repr(C)] will not be checked, as the order of their fields orvariants might be dictated by an external API (application binaryinterface).

Default Ordering and Configuration

As there is no generally applicable rule, and each project may havedifferent requirements, the lint can be configured with highgranularity. The configuration is split into two stages:

  1. Which item kinds that should have an internal order enforced.
  2. Individual ordering rules per item kind.

The item kinds that can be linted are:

  • Module (with customized groupings, alphabetical within - configurable)
  • Trait (with customized order of associated items, alphabetical within)
  • Enum, Impl, Struct (purely alphabetical)

Module Item Order

Due to the large variation of items within modules, the ordering can beconfigured on a very granular level. Item kinds can be grouped togetherarbitrarily, items within groups will be ordered alphabetically. Thefollowing table shows the default groupings:

GroupItem Kinds
modules“mod”, “foreign_mod”
use“use”
macros“macro”
global_asm“global_asm”
UPPER_SNAKE_CASE“static”, “const”
PascalCase“ty_alias”, “opaque_ty”, “enum”, “struct”, “union”, “trait”, “trait_alias”, “impl”
lower_snake_case“fn”

The groups’ names are arbitrary and can be changed to suit theconventions that should be enforced for a specific project.

All item kinds must be accounted for to create an enforceable lintingrule set. Following are some example configurations that may be useful.

Example:module inclusions and use statements to be at the top

module-item-order-groupings = [    [ "modules", [ "extern_crate", "mod", "foreign_mod" ], ],    [ "use", [ "use", ], ],    [ "everything_else", [ "macro", "global_asm", "static", "const", "ty_alias", "enum", "struct", "union", "trait", "trait_alias", "impl", "fn", ], ],]

Example:only consts and statics should be alphabetically ordered

It is also possible to configure a selection of module item groups thatshould be ordered alphabetically. This may be useful if for examplestatics and consts should be ordered, but the rest should be left open.

module-items-ordered-within-groupings = ["UPPER_SNAKE_CASE"]

Known Problems

Performance Impact

Keep in mind, that ordering source code alphabetically can lead toreduced performance in cases where the most commonly used enum variantisn’t the first entry anymore, and similar optimizations that can reducebranch misses, cache locality and such. Either don’t use this lint ifthat’s relevant, or disable the lint in modules or items specificallywhere it matters. Other solutions can be to use profile guidedoptimization (PGO), post-link optimization (e.g. using BOLT for LLVM),or other advanced optimization methods. A good starting point to diginto optimization iscargo-pgo.

Lints on a Contains basis

The lint can be disabled only on a “contains” basis, but not per elementwithin a “container”, e.g. the lint works per-module, per-struct,per-enum, etc. but not for “don’t order this particular enum variant”.

Module documentation

Module level rustdoc comments are not part of the resulting syntax treeand as such cannot be linted from withincheck_mod. Instead, therustdoc::missing_documentation lint may be used.

Module Tests

This lint does not implement detection of module tests (or other featuredependent elements for that matter). To lint the location of mod tests,the lintitems_after_test_module can be used instead.

Example

trait TraitUnordered {    const A: bool;    const C: bool;    const B: bool;    type SomeType;    fn a();    fn c();    fn b();}

Use instead:

trait TraitOrdered {    const A: bool;    const B: bool;    const C: bool;    type SomeType;    fn a();    fn b();    fn c();}

Configuration

  • module-item-order-groupings: The named groupings of different source item kinds within modules.

    (default:[["modules", ["extern_crate", "mod", "foreign_mod"]], ["use", ["use"]], ["macros", ["macro"]], ["global_asm", ["global_asm"]], ["UPPER_SNAKE_CASE", ["static", "const"]], ["PascalCase", ["ty_alias", "enum", "struct", "union", "trait", "trait_alias", "impl"]], ["lower_snake_case", ["fn"]]])

  • module-items-ordered-within-groupings: Whether the items within module groups should be ordered alphabetically or not.

This option can be configured to “all”, “none”, or a list of specific grouping names that should be checked(e.g. only “enums”).

(default:"none")

  • source-item-ordering: Which kind of elements should be ordered internally, possible values beingenum,impl,module,struct,trait.

    (default:["enum", "impl", "module", "struct", "trait"])

  • trait-assoc-item-kinds-order: The order of associated items in traits.

    (default:["const", "type", "fn"])

Applicability:Unspecified(?)
Added in:1.84.0
Related Issues
View Source

arc_with_non_send_sync📋
suspiciouswarn

What it does.

This lint warns when you useArc with a type that does not implementSend orSync.

Why is this bad?

Arc<T> is a thread-safeRc<T> and guarantees that updates to the reference counteruse atomic operations. To send anArc<T> across thread boundaries andshare ownership between multiple threads,T must bebothSend andSync,so eitherT should be madeSend + Sync or anRc should be used instead of anArc.

Example

fn main() {    // This is fine, as `i32` implements `Send` and `Sync`.    let a = Arc::new(42);    // `RefCell` is `!Sync`, so either the `Arc` should be replaced with an `Rc`    // or the `RefCell` replaced with something like a `RwLock`    let b = Arc::new(RefCell::new(42));}
Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

arithmetic_side_effects📋
restrictionallow

What it does

Checks any kind of arithmetic operation of any type.

Operators like+,-,* or<< are usually capable of overflowing according to theRustReference,or can panic (/,%).

Known safe built-in types likeWrapping orSaturating, floats, operations in constantenvironments, allowed types and non-constant operations that won’t overflow are ignored.

Why restrict this?

For integers, overflow will trigger a panic in debug builds or wrap the result inrelease mode; division by zero will cause a panic in either mode. As a result, it isdesirable to explicitly call checked, wrapping or saturating arithmetic methods.

Example

// `n` can be any number, including `i32::MAX`.fn foo(n: i32) -> i32 {    n + 1}

Third-party types can also overflow or present unwanted side-effects.

Example

use rust_decimal::Decimal;let _n = Decimal::MAX + Decimal::MAX;

Past names

  • integer_arithmetic

Configuration

  • arithmetic-side-effects-allowed: Suppress checking of the passed type names in all types of operations.

If a specific operation is desired, consider usingarithmetic_side_effects_allowed_binary orarithmetic_side_effects_allowed_unary instead.

Example

arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]

Noteworthy

A type, saySomeType, listed in this configuration has the same behavior of["SomeType" , "*"], ["*", "SomeType"] inarithmetic_side_effects_allowed_binary.

(default:[])

  • arithmetic-side-effects-allowed-binary: Suppress checking of the passed type pair names in binary operations like addition ormultiplication.

Supports the “*” wildcard to indicate that a certain type won’t trigger the lint regardlessof the involved counterpart. For example,["SomeType", "*"] or["*", "AnotherType"].

Pairs are asymmetric, which means that["SomeType", "AnotherType"] is not the same as["AnotherType", "SomeType"].

Example

arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]

(default:[])

  • arithmetic-side-effects-allowed-unary: Suppress checking of the passed type names in unary operations like “negation” (-).

Example

arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]

(default:[])

Applicability:Unspecified(?)
Added in:1.64.0
Related Issues
View Source

as_conversions📋
restrictionallow

What it does

Checks for usage ofas conversions.

Note that this lint is specialized in lintingevery single use ofasregardless of whether good alternatives exist or not. If you want moreprecise lints foras, please consider using these separate lints:

  • clippy::cast_lossless
  • clippy::cast_possible_truncation
  • clippy::cast_possible_wrap
  • clippy::cast_precision_loss
  • clippy::cast_sign_loss
  • clippy::char_lit_as_u8
  • clippy::fn_to_numeric_cast
  • clippy::fn_to_numeric_cast_with_truncation
  • clippy::ptr_as_ptr
  • clippy::unnecessary_cast
  • invalid_reference_casting

There is a good explanation the reason why this lint should work in thisway and how it is usefulin thisissue.

Why restrict this?

as conversions will perform many kinds ofconversions, including silently lossy conversions and dangerous coercions.There are cases when it makes sense to useas, so the lint isAllow by default.

Example

let a: u32;...f(a as u16);

Use instead:

f(a.try_into()?);// orf(a.try_into().expect("Unexpected u16 overflow in f"));
Applicability:Unspecified(?)
Added in:1.41.0
Related Issues
View Source

as_pointer_underscore📋
restrictionallow

What it does

Checks for the usage ofas *const _ oras *mut _ conversion using inferred type.

Why restrict this?

The conversion might include a dangerous cast that might go undetected due to the type being inferred.

Example

fn as_usize<T>(t: &T) -> usize {    // BUG: `t` is already a reference, so we will here    // return a dangling pointer to a temporary value instead    &t as *const _ as usize}

Use instead:

fn as_usize<T>(t: &T) -> usize {    t as *const T as usize}
Applicability:MachineApplicable(?)
Added in:1.85.0
Related Issues
View Source

as_ptr_cast_mut📋
nurseryallow

What it does

Checks for the result of a&self-takingas_ptr being cast to a mutable pointer.

Why is this bad?

Sinceas_ptr takes a&self, the pointer won’t have write permissions unless interiormutability is used, making it unlikely that having it as a mutable pointer is correct.

Example

let mut vec = Vec::<u8>::with_capacity(1);let ptr = vec.as_ptr() as *mut u8;unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR

Use instead:

let mut vec = Vec::<u8>::with_capacity(1);let ptr = vec.as_mut_ptr();unsafe { ptr.write(4) };
Applicability:MaybeIncorrect(?)
Added in:1.66.0
Related Issues
View Source

as_underscore📋
restrictionallow

What it does

Checks for the usage ofas _ conversion using inferred type.

Why restrict this?

The conversion might include lossy conversion or a dangerous cast that might goundetected due to the type being inferred.

The lint is allowed by default as using_ is less wordy than always specifying the type.

Example

fn foo(n: usize) {}let n: u16 = 256;foo(n as _);

Use instead:

fn foo(n: usize) {}let n: u16 = 256;foo(n as usize);
Applicability:MachineApplicable(?)
Added in:1.63.0
Related Issues
View Source

assertions_on_constants📋
stylewarn

What it does

Checks forassert!(true) andassert!(false) calls.

Why is this bad?

Will be optimized out by the compiler or should probably be replaced by apanic!() orunreachable!()

Example

assert!(false)assert!(true)const B: bool = false;assert!(B)
Applicability:Unspecified(?)
Added in:1.34.0
Related Issues
View Source

assertions_on_result_states📋
restrictionallow

What it does

Checks forassert!(r.is_ok()) orassert!(r.is_err()) calls.

Why restrict this?

This form of assertion does not show any of the information present in theResultother than which variant it isn’t.

Known problems

The suggested replacement decreases the readability of code and log output.

Example

assert!(r.is_ok());assert!(r.is_err());

Use instead:

r.unwrap();r.unwrap_err();
Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

assign_op_pattern📋
stylewarn

What it does

Checks fora = a op b ora = b commutative_op apatterns.

Why is this bad?

These can be written as the shortera op= b.

Known problems

While forbidden by the spec,OpAssign traits may haveimplementations that differ from the regularOp impl.

Example

let mut a = 5;let b = 0;// ...a = a + b;

Use instead:

let mut a = 5;let b = 0;// ...a += b;
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

assign_ops📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

Compound operators are harmless and linting on them is not in scope for clippy.

Applicability:Unspecified(?)
Deprecated in:1.30.0
Related Issues

assigning_clones📋
pedanticallow

What it does

Checks for code likefoo = bar.clone();

Why is this bad?

CustomClone::clone_from() orToOwned::clone_into implementations allow the objectsto share resources and therefore avoid allocations.

Example

struct Thing;impl Clone for Thing {    fn clone(&self) -> Self { todo!() }    fn clone_from(&mut self, other: &Self) { todo!() }}pub fn assign_to_ref(a: &mut Thing, b: Thing) {    *a = b.clone();}

Use instead:

struct Thing;impl Clone for Thing {    fn clone(&self) -> Self { todo!() }    fn clone_from(&mut self, other: &Self) { todo!() }}pub fn assign_to_ref(a: &mut Thing, b: Thing) {    a.clone_from(&b);}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:Unspecified(?)
Added in:1.78.0
Related Issues
View Source

async_yields_async📋
correctnessdeny

What it does

Checks for async blocks that yield values of typesthat can themselves be awaited.

Why is this bad?

An await is likely missing.

Example

async fn foo() {}fn bar() {  let x = async {    foo()  };}

Use instead:

async fn foo() {}fn bar() {  let x = async {    foo().await  };}
Applicability:MaybeIncorrect(?)
Added in:1.48.0
Related Issues
View Source

await_holding_invalid_type📋
suspiciouswarn

What it does

Allows users to configure types which should not be held across awaitsuspension points.

Why is this bad?

There are some types which are perfectly safe to use concurrently froma memory access perspective, but that will cause bugs at runtime ifthey are held in such a way.

Example

await-holding-invalid-types = [  # You can specify a type name  "CustomLockType",  # You can (optionally) specify a reason  { path = "OtherCustomLockType", reason = "Relies on a thread local" }]
struct CustomLockType;struct OtherCustomLockType;async fn foo() {  let _x = CustomLockType;  let _y = OtherCustomLockType;  baz().await; // Lint violation}

Configuration

  • await-holding-invalid-types: The list of types which may not be held across an await point.

    (default:[])

Applicability:Unspecified(?)
Added in:1.62.0
Related Issues
View Source

await_holding_lock📋
suspiciouswarn

What it does

Checks for calls toawait while holding a non-async-awareMutexGuard.

Why is this bad?

The Mutex types found instd::sync andparking_lot arenot designed to operate in an async context across await points.

There are two potential solutions. One is to use an async-awareMutextype. Many asynchronous foundation crates provide such aMutex type.The other solution is to ensure the mutex is unlocked before callingawait, either by introducing a scope or an explicit call toDrop::drop.

Known problems

Will report false positive for explicitly dropped guards(#6446). Aworkaround for this is to wrap the.lock() call in a block instead ofexplicitly dropping the guard.

Example

async fn foo(x: &Mutex<u32>) {  let mut guard = x.lock().unwrap();  *guard += 1;  baz().await;}async fn bar(x: &Mutex<u32>) {  let mut guard = x.lock().unwrap();  *guard += 1;  drop(guard); // explicit drop  baz().await;}

Use instead:

async fn foo(x: &Mutex<u32>) {  {    let mut guard = x.lock().unwrap();    *guard += 1;  }  baz().await;}async fn bar(x: &Mutex<u32>) {  {    let mut guard = x.lock().unwrap();    *guard += 1;  } // guard dropped here at end of scope  baz().await;}
Applicability:Unspecified(?)
Added in:1.45.0
Related Issues
View Source

await_holding_refcell_ref📋
suspiciouswarn

What it does

Checks for calls toawait while holding aRefCell,Ref, orRefMut.

Why is this bad?

RefCell refs only check for exclusive mutable accessat runtime. Holding aRefCell ref across an await suspension pointrisks panics from a mutable ref shared while other refs are outstanding.

Known problems

Will report false positive for explicitly dropped refs(#6353). A workaround for this isto wrap the.borrow[_mut]() call in a block instead of explicitly dropping the ref.

Example

async fn foo(x: &RefCell<u32>) {  let mut y = x.borrow_mut();  *y += 1;  baz().await;}async fn bar(x: &RefCell<u32>) {  let mut y = x.borrow_mut();  *y += 1;  drop(y); // explicit drop  baz().await;}

Use instead:

async fn foo(x: &RefCell<u32>) {  {     let mut y = x.borrow_mut();     *y += 1;  }  baz().await;}async fn bar(x: &RefCell<u32>) {  {    let mut y = x.borrow_mut();    *y += 1;  } // y dropped here at end of scope  baz().await;}
Applicability:Unspecified(?)
Added in:1.49.0
Related Issues
View Source

bad_bit_mask📋
correctnessdeny

What it does

Checks for incompatible bit masks in comparisons.

The formula for detecting if an expression of the type_ <bit_op> m <cmp_op> c (where<bit_op> is one of {&,|} and<cmp_op> is one of{!=,>=,>,!=,>=,>}) can be determined from the followingtable:

ComparisonBit OpExampleis alwaysFormula
== or!=&x & 2 == 3falsec & m != c
< or>=&x & 2 < 3truem < c
> or<=&x & 1 > 1falsem <= c
== or!=|x | 1 == 0falsec | m != c
< or>=|x | 1 < 1falsem >= c
<= or>|x | 1 > 0truem > c

Why is this bad?

If the bits that the comparison cares about are alwaysset to zero or one by the bit mask, the comparison is constanttrue orfalse (depending on mask, compared value, and operators).

So the code is actively misleading, and the only reason someone would writethis intentionally is to win an underhanded Rust contest or create atest-case for this lint.

Example

if (x & 1 == 2) { }
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

big_endian_bytes📋
restrictionallow

What it does

Checks for the usage of theto_be_bytes method and/or the functionfrom_be_bytes.

Why restrict this?

To ensure use of little-endian or the target’s endianness rather than big-endian.

Example

let _x = 2i32.to_be_bytes();let _y = 2i64.to_be_bytes();
Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

bind_instead_of_map📋
complexitywarn

What it does

Checks for usage of_.and_then(|x| Some(y)),_.and_then(|x| Ok(y))or_.or_else(|x| Err(y)).

Why is this bad?

This can be written more concisely as_.map(|x| y) or_.map_err(|x| y).

Example

let _ = opt().and_then(|s| Some(s.len()));let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });

The correct use would be:

let _ = opt().map(|s| s.len());let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });

Past names

  • option_and_then_some
Applicability:MachineApplicable(?)
Added in:1.45.0
Related Issues
View Source

blanket_clippy_restriction_lints📋
suspiciouswarn

What it does

Checks forwarn/deny/forbid attributes targeting the whole clippy::restriction category.

Why is this bad?

Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.These lints should only be enabled on a lint-by-lint basis and with careful consideration.

Example

#![deny(clippy::restriction)]

Use instead:

#![deny(clippy::as_conversions)]
Applicability:Unspecified(?)
Added in:1.47.0
Related Issues
View Source

blocks_in_conditions📋
stylewarn

What it does

Checks forif andmatch conditions that use blocks containing anexpression, statements or conditions that use closures with blocks.

Why is this bad?

Style, using blocks in the condition makes it hard to read.

Examples

if { true } { /* ... */ }if { let x = somefunc(); x } { /* ... */ }match { let e = somefunc(); e } {    // ...}

Use instead:

if true { /* ... */ }let res = { let x = somefunc(); x };if res { /* ... */ }let res = { let e = somefunc(); e };match res {    // ...}

Past names

  • block_in_if_condition_expr
  • block_in_if_condition_stmt
  • blocks_in_if_conditions
Applicability:MachineApplicable(?)
Added in:1.45.0
Related Issues
View Source

bool_assert_comparison📋
stylewarn

What it does

This lint warns about boolean comparisons in assert-like macros.

Why is this bad?

It is shorter to use the equivalent.

Example

assert_eq!("a".is_empty(), false);assert_ne!("a".is_empty(), true);

Use instead:

assert!(!"a".is_empty());
Applicability:MachineApplicable(?)
Added in:1.53.0
Related Issues
View Source

bool_comparison📋
complexitywarn

What it does

Checks for expressions of the formx == true,x != true and order comparisons such asx < true (or vice versa) andsuggest using the variable directly.

Why is this bad?

Unnecessary code.

Example

if x == true {}if y == false {}

usex directly:

if x {}if !y {}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

bool_to_int_with_if📋
pedanticallow

What it does

Instead of using an if statement to convert a bool to an int,this lint suggests using afrom() function or anas coercion.

Why is this bad?

Coercion orfrom() is another way to convert bool to a number.Both methods are guaranteed to return 1 for true, and 0 for false.

See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E

Example

if condition {    1_i64} else {    0};

Use instead:

i64::from(condition);

or

condition as i64;
Applicability:MachineApplicable(?)
Added in:1.65.0
Related Issues
View Source

borrow_as_ptr📋
pedanticallow

What it does

Checks for the usage of&expr as *const T or&mut expr as *mut T, and suggest using&raw const or&raw mut instead.

Why is this bad?

This would improve readability and avoid creating a referencethat points to an uninitialized value or unaligned place.Read the&raw explanation in the Reference for more information.

Example

let val = 1;let p = &val as *const i32;let mut val_mut = 1;let p_mut = &mut val_mut as *mut i32;

Use instead:

let val = 1;let p = &raw const val;let mut val_mut = 1;let p_mut = &raw mut val_mut;

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.60.0
Related Issues
View Source

borrow_deref_ref📋
complexitywarn

What it does

Checks for&*(&T).

Why is this bad?

Dereferencing and then borrowing a reference value has no effect in most cases.

Known problems

False negative on such code:

let x = &12;let addr_x = &x as *const _ as usize;let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered.                                        // But if we fix it, assert will fail.assert_ne!(addr_x, addr_y);

Example

let s = &String::new();let a: &String = &* s;

Use instead:

let a: &String = s;
Applicability:MachineApplicable(?)
Added in:1.63.0
Related Issues
View Source

borrow_interior_mutable_const📋
stylewarn

What it does

Checks for a borrow of a named constant with interior mutability.

Why is this bad?

Named constants are copied at every use site which means any change to their valuewill be lost after the newly created value is dropped. e.g.

use core::sync::atomic::{AtomicUsize, Ordering};const ATOMIC: AtomicUsize = AtomicUsize::new(0);fn add_one() -> usize {    // This will always return `0` since `ATOMIC` is copied before it's borrowed    // for use by `fetch_add`.    ATOMIC.fetch_add(1, Ordering::AcqRel)}

Known problems

This lint does not, and cannot in general, determine if the borrow of the constantis used in a way which causes a mutation. e.g.

use core::cell::Cell;const CELL: Cell<usize> = Cell::new(0);fn get_cell() -> Cell<usize> {    // This is fine. It borrows a copy of `CELL`, but never mutates it through the    // borrow.    CELL.clone()}

There also exists types which contain private fields with interior mutability, butno way to both create a value as a constant and modify any mutable field using thetype’s public interface (e.g.bytes::Bytes). As there is no reasonable way toscan a crate’s interface to see if this is the case, all such types will be linted.If this happens use theignore-interior-mutability configuration option to allowthe type.

Example

use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchangedassert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct

Use instead:

use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);static STATIC_ATOM: AtomicUsize = CONST_ATOM;STATIC_ATOM.store(9, SeqCst);assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance

Configuration

  • ignore-interior-mutability: A list of paths to types that should be treated as if they do not contain interior mutability

    (default:["bytes::Bytes"])

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

borrowed_box📋
complexitywarn

What it does

Checks for usage of&Box<T> anywhere in the code.Check theBox documentation for more information.

Why is this bad?

A&Box<T> parameter requires the function caller to boxT first before passing it to a function.Using&T defines a concrete type for the parameter and generalizes the function, this would alsoauto-deref to&T at the function call site if passed a&Box<T>.

Example

fn foo(bar: &Box<T>) { ... }

Better:

fn foo(bar: &T) { ... }
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

box_collection📋
perfwarn

What it does

Checks for usage ofBox<T> where T is a collection such as Vec anywhere in the code.Check theBox documentation for more information.

Why is this bad?

Collections already keeps their contents in a separate area onthe heap. So if youBox them, you just add another level of indirectionwithout any benefit whatsoever.

Example

struct X {    values: Box<Vec<Foo>>,}

Better:

struct X {    values: Vec<Foo>,}

Past names

  • box_vec

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:1.57.0
Related Issues
View Source

box_default📋
stylewarn

What it does

checks forBox::new(Default::default()), which can be written asBox::default().

Why is this bad?

Box::default() is equivalent and more concise.

Example

let x: Box<String> = Box::new(Default::default());

Use instead:

let x: Box<String> = Box::default();
Applicability:MachineApplicable(?)
Added in:1.66.0
Related Issues
View Source

boxed_local📋
perfwarn

What it does

Checks for usage ofBox<T> where an unboxedT wouldwork fine.

Why is this bad?

This is an unnecessary allocation, and bad forperformance. It is only necessary to allocate if you wish to move the boxinto something.

Example

fn foo(x: Box<u32>) {}

Use instead:

fn foo(x: u32) {}

Configuration

  • too-large-for-stack: The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap

    (default:200)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

branches_sharing_code📋
nurseryallow

What it does

Checks if theif andelse block contain shared code that can bemoved out of the blocks.

Why is this bad?

Duplicate code is less maintainable.

Example

let foo = if … {    println!("Hello World");    13} else {    println!("Hello World");    42};

Use instead:

println!("Hello World");let foo = if … {    13} else {    42};
Applicability:Unspecified(?)
Added in:1.53.0
Related Issues
View Source

builtin_type_shadow📋
stylewarn

What it does

Warns if a generic shadows a built-in type.

Why is this bad?

This gives surprising type errors.

Example

impl<u32> Foo<u32> {    fn impl_func(&self) -> u32 {        42    }}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

byte_char_slices📋
stylewarn

What it does

Checks for hard to read slices of byte characters, that could be more easily expressed as abyte string.

Why is this bad?

Potentially makes the string harder to read.

Example

&[b'H', b'e', b'l', b'l', b'o'];

Use instead:

b"Hello"
Applicability:MachineApplicable(?)
Added in:1.81.0
Related Issues
View Source

bytes_count_to_len📋
complexitywarn

What it does

It checks forstr::bytes().count() and suggests replacing it withstr::len().

Why is this bad?

str::bytes().count() is longer and may not be as performant as usingstr::len().

Example

"hello".bytes().count();String::from("hello").bytes().count();

Use instead:

"hello".len();String::from("hello").len();
Applicability:MachineApplicable(?)
Added in:1.62.0
Related Issues
View Source

bytes_nth📋
stylewarn

What it does

Checks for the use of.bytes().nth().

Why is this bad?

.as_bytes().get() is more efficient and morereadable.

Example

"Hello".bytes().nth(3);

Use instead:

"Hello".as_bytes().get(3);
Applicability:MachineApplicable(?)
Added in:1.52.0
Related Issues
View Source

cargo_common_metadata📋
cargoallow

What it does

Checks to see if all common metadata is defined inCargo.toml. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata

Why is this bad?

It will be more difficult for users to discover thepurpose of the crate, and key information related to it.

Example

[package]name = "clippy"version = "0.0.212"repository = "https://github.com/rust-lang/rust-clippy"readme = "README.md"license = "MIT OR Apache-2.0"keywords = ["clippy", "lint", "plugin"]categories = ["development-tools", "development-tools::cargo-plugins"]

Should include a description field like:

[package]name = "clippy"version = "0.0.212"description = "A bunch of helpful lints to avoid common pitfalls in Rust"repository = "https://github.com/rust-lang/rust-clippy"readme = "README.md"license = "MIT OR Apache-2.0"keywords = ["clippy", "lint", "plugin"]categories = ["development-tools", "development-tools::cargo-plugins"]

Configuration

  • cargo-ignore-publish: For internal testing only, ignores the currentpublish settings in the Cargo manifest.

    (default:false)

Applicability:Unspecified(?)
Added in:1.32.0
Related Issues
View Source

case_sensitive_file_extension_comparisons📋
pedanticallow

What it does

Checks for calls toends_with with possible file extensionsand suggests to use a case-insensitive approach instead.

Why is this bad?

ends_with is case-sensitive and may not detect files with a valid extension.

Example

fn is_rust_file(filename: &str) -> bool {    filename.ends_with(".rs")}

Use instead:

fn is_rust_file(filename: &str) -> bool {    let filename = std::path::Path::new(filename);    filename.extension()        .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))}
Applicability:MaybeIncorrect(?)
Added in:1.51.0
Related Issues
View Source

cast_abs_to_unsigned📋
suspiciouswarn

What it does

Checks for usage of theabs() method that cast the result to unsigned.

Why is this bad?

Theunsigned_abs() method avoids panic when called on the MIN value.

Example

let x: i32 = -42;let y: u32 = x.abs() as u32;

Use instead:

let x: i32 = -42;let y: u32 = x.unsigned_abs();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.62.0
Related Issues
View Source

cast_enum_constructor📋
suspiciouswarn

What it does

Checks for casts from an enum tuple constructor to an integer.

Why is this bad?

The cast is easily confused with casting a c-like enum value to an integer.

Example

enum E { X(i32) };let _ = E::X as usize;
Applicability:Unspecified(?)
Added in:1.61.0
Related Issues
View Source

cast_enum_truncation📋
suspiciouswarn

What it does

Checks for casts from an enum type to an integral type that will definitely truncate thevalue.

Why is this bad?

The resulting integral value will not match the value of the variant it came from.

Example

enum E { X = 256 };let _ = E::X as u8;
Applicability:Unspecified(?)
Added in:1.61.0
Related Issues
View Source

cast_lossless📋
pedanticallow

What it does

Checks for casts between numeric types that can be replaced by safeconversion functions.

Why is this bad?

Rust’sas keyword will perform many kinds of conversions, includingsilently lossy conversions. Conversion functions such asi32::fromwill only perform lossless conversions. Using the conversion functionsprevents conversions from becoming silently lossy if the input typesever change, and makes it clear for people reading the code that theconversion is lossless.

Example

fn as_u64(x: u8) -> u64 {    x as u64}

Using::from would look like this:

fn as_u64(x: u8) -> u64 {    u64::from(x)}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

cast_nan_to_int📋
suspiciouswarn

What it does

Checks for a known NaN float being cast to an integer

Why is this bad?

NaNs are cast into zero, so one could simply use this and make thecode more readable. The lint could also hint at a programmer error.

Example

let _ = (0.0_f32 / 0.0) as u64;

Use instead:

let _ = 0_u64;
Applicability:Unspecified(?)
Added in:1.66.0
Related Issues
View Source

cast_possible_truncation📋
pedanticallow

What it does

Checks for casts between numeric types that maytruncate large values. This is expected behavior, so the cast isAllow bydefault. It suggests user either explicitly ignore the lint,or usetry_from() and handle the truncation, default, or panic explicitly.

Why is this bad?

In some problem domains, it is good practice to avoidtruncation. This lint can be activated to help assess where additionalchecks could be beneficial.

Example

fn as_u8(x: u64) -> u8 {    x as u8}

Use instead:

fn as_u8(x: u64) -> u8 {    if let Ok(x) = u8::try_from(x) {        x    } else {        todo!();    }}// Or#[allow(clippy::cast_possible_truncation)]fn as_u16(x: u64) -> u16 {    x as u16}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

cast_possible_wrap📋
pedanticallow

What it does

Checks for casts from an unsigned type to a signed type ofthe same size, or possibly smaller due to target-dependent integers.Performing such a cast is a no-op for the compiler (that is, nothing ischanged at the bit level), and the binary representation of the value isreinterpreted. This can cause wrapping if the value is too bigfor the target signed type. However, the cast works as defined, so this lintisAllow by default.

Why is this bad?

While such a cast is not bad in itself, the results canbe surprising when this is not the intended behavior:

Example

let _ = u32::MAX as i32; // will yield a value of `-1`

Use instead:

let _ = i32::try_from(u32::MAX).ok();
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

cast_precision_loss📋
pedanticallow

What it does

Checks for casts from any numeric type to a float type wherethe receiving type cannot store all values from the original type withoutrounding errors. This possible rounding is to be expected, so this lint isAllow by default.

Basically, this warns on casting any integer with 32 or more bits tof32or any 64-bit integer tof64.

Why is this bad?

It’s not bad at all. But in some applications it can behelpful to know where precision loss can take place. This lint can help findthose places in the code.

Example

let x = u64::MAX;x as f64;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

cast_ptr_alignment📋
pedanticallow

What it does

Checks for casts, usingas orpointer::cast, from aless strictly aligned pointer to a more strictly aligned pointer.

Why is this bad?

Dereferencing the resulting pointer may be undefined behavior.

Known problems

Usingstd::ptr::read_unaligned andstd::ptr::write_unaligned orsimilar on the resulting pointer is fine. Is over-zealous: casts withmanual alignment checks or casts likeu64 ->u8 ->u16 can befine. Miri is able to do a more in-depth analysis.

Example

let _ = (&1u8 as *const u8) as *const u16;let _ = (&mut 1u8 as *mut u8) as *mut u16;(&1u8 as *const u8).cast::<u16>();(&mut 1u8 as *mut u8).cast::<u16>();
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

cast_sign_loss📋
pedanticallow

What it does

Checks for casts from a signed to an unsigned numerictype. In this case, negative values wrap around to large positive values,which can be quite surprising in practice. However, since the cast works asdefined, this lint isAllow by default.

Why is this bad?

Possibly surprising results. You can activate this lintas a one-time check to see where numeric wrapping can arise.

Example

let y: i8 = -1;y as u64; // will return 18446744073709551615
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

cast_slice_different_sizes📋
correctnessdeny

What it does

Checks foras casts between raw pointers to slices with differently sized elements.

Why is this bad?

The produced raw pointer to a slice does not update its length metadata. The producedpointer will point to a different number of bytes than the original pointer because thelength metadata of a raw slice pointer is in elements rather than bytes.Producing a slice reference from the raw pointer will either create a slice withless data (which can be surprising) or create a slice with more data and cause Undefined Behavior.

Example

// Missing data

let a = [1_i32, 2, 3, 4];let p = &a as *const [i32] as *const [u8];unsafe {    println!("{:?}", &*p);}

// Undefined Behavior (note: also potential alignment issues)

let a = [1_u8, 2, 3, 4];let p = &a as *const [u8] as *const [u32];unsafe {    println!("{:?}", &*p);}

Instead useptr::slice_from_raw_parts to construct a slice from a data pointer and the correct length

let a = [1_i32, 2, 3, 4];let old_ptr = &a as *const [i32];// The data pointer is cast to a pointer to the target `u8` not `[u8]`// The length comes from the known length of 4 i32s times the 4 bytes per i32let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);unsafe {    println!("{:?}", &*new_ptr);}
Applicability:HasPlaceholders(?)
Added in:1.61.0
Related Issues
View Source

cast_slice_from_raw_parts📋
suspiciouswarn

What it does

Checks for a raw slice being cast to a slice pointer

Why is this bad?

This can result in multiple&mut references to the same location when only a pointer isrequired.ptr::slice_from_raw_parts is a safe alternative that doesn’t requirethe samesafety requirements to be upheld.

Example

let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;

Use instead:

let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
Applicability:MachineApplicable(?)
Added in:1.65.0
Related Issues
View Source

cfg_not_test📋
restrictionallow

What it does

Checks for usage ofcfg that excludes code fromtest builds. (i.e.,#[cfg(not(test))])

Why is this bad?

This may give the false impression that a codebase has 100% coverage, yet actually has untested code.Enabling this also guards against excessive mockery as well, which is an anti-pattern.

Example

#[cfg(not(test))]important_check(); // I'm not actually tested, but not including me will falsely increase coverage!

Use instead:

important_check();
Applicability:Unspecified(?)
Added in:1.81.0
Related Issues
View Source

char_indices_as_byte_indices📋
correctnessdeny

What it does

Checks for usage of a character position yielded by.chars().enumerate() in a context where abyte index is expected,such as an argument to a specificstr method or indexing into astr orString.

Why is this bad?

A character (more specifically, a Unicode scalar value) that is yielded bystr::chars can take up multiple bytes,so a character position does not necessarily have the same byte index at which the character is stored.Thus, using the character position where a byte index is expected can unexpectedly return wrong valuesor panic when the string consists of multibyte characters.

For example, the charactera inäa is stored at byte index 2 but has the character position 1.Using the character position 1 to index into the string will lead to a panic as it is in the middle of the first character.

Instead of.chars().enumerate(), the correct iterator to use is.char_indices(), which yields byte indices.

This pattern is technically fine if the strings are known to only use the ASCII subset,though in those cases it would be better to usebytes() directly to make the intent clearer,but there is also no downside to just using.char_indices() directly and supporting non-ASCII strings.

You may also want to read thechapter on strings in the Rust Bookwhich goes into this in more detail.

Example

for (idx, c) in s.chars().enumerate() {    let _ = s[idx..]; // ⚠️ Panics for strings consisting of multibyte characters}

Use instead:

for (idx, c) in s.char_indices() {    let _ = s[idx..];}
Applicability:MaybeIncorrect(?)
Added in:1.88.0
Related Issues
View Source

char_lit_as_u8📋
complexitywarn

What it does

Checks for expressions where a character literal is casttou8 and suggests using a byte literal instead.

Why is this bad?

In general, casting values to smaller types iserror-prone and should be avoided where possible. In the particular case ofconverting a character literal tou8, it is easy to avoid by just using abyte literal instead. As an added bonus,b'a' is also slightly shorterthan'a' as u8.

Example

'x' as u8

A better version, using the byte literal:

b'x'
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

chars_last_cmp📋
stylewarn

What it does

Checks for usage of_.chars().last() or_.chars().next_back() on astr to check if it ends with a given char.

Why is this bad?

Readability, this can be written more concisely as_.ends_with(_).

Example

name.chars().last() == Some('_') || name.chars().next_back() == Some('-');

Use instead:

name.ends_with('_') || name.ends_with('-');
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

chars_next_cmp📋
stylewarn

What it does

Checks for usage of.chars().next() on astr to checkif it starts with a given char.

Why is this bad?

Readability, this can be written more concisely as_.starts_with(_).

Example

let name = "foo";if name.chars().next() == Some('_') {};

Use instead:

let name = "foo";if name.starts_with('_') {};
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

checked_conversions📋
pedanticallow

What it does

Checks for explicit bounds checking when casting.

Why is this bad?

Reduces the readability of statements & is error prone.

Example

foo <= i32::MAX as u32;

Use instead:

i32::try_from(foo).is_ok();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.37.0
Related Issues
View Source

clear_with_drain📋
nurseryallow

What it does

Checks for usage of.drain(..) for the sole purpose of clearing a container.

Why is this bad?

This creates an unnecessary iterator that is dropped immediately.

Calling.clear() also makes the intent clearer.

Example

let mut v = vec![1, 2, 3];v.drain(..);

Use instead:

let mut v = vec![1, 2, 3];v.clear();
Applicability:MachineApplicable(?)
Added in:1.70.0
Related Issues
View Source

clone_on_copy📋
complexitywarn

What it does

Checks for usage of.clone() on aCopy type.

Why is this bad?

The only reasonCopy types implementClone is forgenerics, not for using theclone method on a concrete type.

Example

42u64.clone();
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

clone_on_ref_ptr📋
restrictionallow

What it does

Checks for usage of.clone() on a ref-counted pointer,(Rc,Arc,rc::Weak, orsync::Weak), and suggests calling Clone via unifiedfunction syntax instead (e.g.,Rc::clone(foo)).

Why restrict this?

Calling.clone() on anRc,Arc, orWeakcan obscure the fact that only the pointer is being cloned, not the underlyingdata.

Example

let x = Rc::new(1);x.clone();

Use instead:

Rc::clone(&x);
Applicability:HasPlaceholders(?)
Added in:pre 1.29.0
Related Issues
View Source

cloned_instead_of_copied📋
pedanticallow

What it does

Checks for usage ofcloned() on anIterator orOption wherecopied() could be used instead.

Why is this bad?

copied() is better because it guarantees that the type being clonedimplementsCopy.

Example

[1, 2, 3].iter().cloned();

Use instead:

[1, 2, 3].iter().copied();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.53.0
Related Issues
View Source

cloned_ref_to_slice_refs📋
perfwarn

What it does

Checks for slice references with cloned references such as&[f.clone()].

Why is this bad

A reference does not need to be owned in order to be used as a slice.

Known problems

This lint does not know whether or not a clone implementation has side effects.

Example

let data = 10;let data_ref = &data;take_slice(&[data_ref.clone()]);

Use instead:

use std::slice;let data = 10;let data_ref = &data;take_slice(slice::from_ref(data_ref));
Applicability:MaybeIncorrect(?)
Added in:1.89.0
Related Issues
View Source

cmp_null📋
stylewarn

What it does

This lint checks for equality comparisons withptr::null

Why is this bad?

It’s easier and more readable to use the inherent.is_null()method instead

Example

use std::ptr;if x == ptr::null {    // ..}

Use instead:

if x.is_null() {    // ..}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

cmp_owned📋
perfwarn

What it does

Checks for conversions to owned values just for the sakeof a comparison.

Why is this bad?

The comparison can operate on a reference, so creatingan owned value effectively throws it away directly afterwards, which isneedlessly consuming code and heap space.

Example

if x.to_owned() == y {}

Use instead:

if x == y {}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

coerce_container_to_any📋
nurseryallow

What it does

Protects against unintended coercion of references to container types to&dyn Any when thecontainer type dereferences to adyn Any which could be directly referenced instead.

Why is this bad?

The intention is usually to get a reference to thedyn Any the value dereferences to,rather than coercing a reference to the container itself to&dyn Any.

Example

BecauseBox<dyn Any> itself implementsAny,&Box<dyn Any>can be coerced to an&dyn Any which refers totheBox itself, rather than theinnerdyn Any.

let x: Box<dyn Any> = Box::new(0u32);let dyn_any_of_box: &dyn Any = &x;// Fails as we have a &dyn Any to the Box, not the u32assert_eq!(dyn_any_of_box.downcast_ref::<u32>(), None);

Use instead:

let x: Box<dyn Any> = Box::new(0u32);let dyn_any_of_u32: &dyn Any = &*x;// Succeeds since we have a &dyn Any to the inner u32!assert_eq!(dyn_any_of_u32.downcast_ref::<u32>(), Some(&0u32));
Applicability:MaybeIncorrect(?)
Added in:1.89.0
Related Issues
View Source

cognitive_complexity📋
restrictionallow

What it does

We used to think it measured how hard a method is to understand.

Why is this bad?

Ideally, we would like to be able to measure how hard a function isto understand given its context (what we call its Cognitive Complexity).But that’s not what this lint does. See “Known problems”

Known problems

The true Cognitive Complexity of a method is not something we cancalculate using modern technology. This lint has been left inrestriction so as to not mislead users into using this lint as ameasurement tool.

For more detailed information, seerust-clippy#3793

Lints to consider instead of this

Past names

  • cyclomatic_complexity

Configuration

  • cognitive-complexity-threshold: The maximum cognitive complexity a function can have

    (default:25)

Applicability:Unspecified(?)
Added in:1.35.0
Related Issues
View Source

collapsible_else_if📋
stylewarn

What it does

Checks for collapsibleelse { if ... } expressionsthat can be collapsed toelse if ....

Why is this bad?

Eachif-statement adds one level of nesting, whichmakes code look more complex than it really is.

Example

if x {    …} else {    if y {        …    }}

Should be written:

if x {    …} else if y {    …}

Configuration

  • lint-commented-code: Whether collapsibleif andelse if chains are linted if they contain comments inside the partsthat would be collapsed.

    (default:false)

Applicability:MachineApplicable(?)
Added in:1.51.0
Related Issues
View Source

collapsible_if📋
stylewarn

What it does

Checks for nestedif statements which can be collapsedby&&-combining their conditions.

Why is this bad?

Eachif-statement adds one level of nesting, whichmakes code look more complex than it really is.

Example

if x {    if y {        // …    }}

Use instead:

if x && y {    // …}

Configuration

  • lint-commented-code: Whether collapsibleif andelse if chains are linted if they contain comments inside the partsthat would be collapsed.

    (default:false)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

collapsible_match📋
stylewarn

What it does

Finds nestedmatch orif let expressions where the patterns may be “collapsed” togetherwithout adding any branches.

Note that this lint is not intended to findall cases where nested match patterns can be merged, but onlycases where merging would most likely make the code more readable.

Why is this bad?

It is unnecessarily verbose and complex.

Example

fn func(opt: Option<Result<u64, String>>) {    let n = match opt {        Some(n) => match n {            Ok(n) => n,            _ => return,        }        None => return,    };}

Use instead:

fn func(opt: Option<Result<u64, String>>) {    let n = match opt {        Some(Ok(n)) => n,        _ => return,    };}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:Unspecified(?)
Added in:1.50.0
Related Issues
View Source

collapsible_str_replace📋
perfwarn

What it does

Checks for consecutive calls tostr::replace (2 or more)that can be collapsed into a single call.

Why is this bad?

Consecutivestr::replace calls scan the string multiple timeswith repetitive code.

Example

let hello = "hesuo worpd"    .replace('s', "l")    .replace("u", "l")    .replace('p', "l");

Use instead:

let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l");

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.65.0
Related Issues
View Source

collection_is_never_read📋
nurseryallow

What it does

Checks for collections that are never queried.

Why is this bad?

Putting effort into constructing a collection but then never querying it might indicate thatthe author forgot to do whatever they intended to do with the collection. Example: Clonea vector, sort it for iteration, but then mistakenly iterate the original vectorinstead.

Example

let mut sorted_samples = samples.clone();sorted_samples.sort();for sample in &samples { // Oops, meant to use `sorted_samples`.    println!("{sample}");}

Use instead:

let mut sorted_samples = samples.clone();sorted_samples.sort();for sample in &sorted_samples {    println!("{sample}");}
Applicability:Unspecified(?)
Added in:1.70.0
Related Issues
View Source

comparison_chain📋
pedanticallow

What it does

Checks comparison chains written withif that can berewritten withmatch andcmp.

Why is this bad?

if is not guaranteed to be exhaustive and conditionals can getrepetitive

Known problems

The match statement may be slower due to the compilernot inlining the call to cmp. See issue#5354

Example

fn f(x: u8, y: u8) {    if x > y {        a()    } else if x < y {        b()    } else {        c()    }}

Use instead:

use std::cmp::Ordering;fn f(x: u8, y: u8) {     match x.cmp(&y) {         Ordering::Greater => a(),         Ordering::Less => b(),         Ordering::Equal => c()     }}
Applicability:HasPlaceholders(?)
Added in:1.40.0
Related Issues
View Source

comparison_to_empty📋
stylewarn

What it does

Checks for comparing to an empty slice such as"" or[],and suggests using.is_empty() where applicable.

Why is this bad?

Some structures can answer.is_empty() much fasterthan checking for equality. So it is good to get into the habit of using.is_empty(), and having it is cheap.Besides, it makes the intent clearer than a manual comparison in some contexts.

Example

if s == "" {    ..}if arr == [] {    ..}

Use instead:

if s.is_empty() {    ..}if arr.is_empty() {    ..}
Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

confusing_method_to_numeric_cast📋
suspiciouswarn

What it does

Checks for casts of a primitive method pointer likemax/min to any integer type.

Why restrict this?

Casting a function pointer to an integer can have surprising results and can occuraccidentally if parentheses are omitted from a function call. If you aren’t doing anythinglow-level with function pointers then you can opt out of casting functions to integers inorder to avoid mistakes. Alternatively, you can use this lint to audit all uses of functionpointer casts in your code.

Example

let _ = u16::max as usize;

Use instead:

let _ = u16::MAX as usize;
Applicability:MaybeIncorrect(?)
Added in:1.89.0
Related Issues
View Source

const_is_empty📋
suspiciouswarn

What it does

It identifies calls to.is_empty() on constant values.

Why is this bad?

String literals and constant values are known at compile time. Checking if theyare empty will always return the same value. This might not be the intention ofthe expression.

Example

let value = "";if value.is_empty() {    println!("the string is empty");}

Use instead:

println!("the string is empty");
Applicability:Unspecified(?)
Added in:1.79.0
Related Issues
View Source

copy_iterator📋
pedanticallow

What it does

Checks for types that implementCopy as well asIterator.

Why is this bad?

Implicit copies can be confusing when working withiterator combinators.

Example

#[derive(Copy, Clone)]struct Countdown(u8);impl Iterator for Countdown {    // ...}let a: Vec<_> = my_iterator.take(1).collect();let b: Vec<_> = my_iterator.collect();
Applicability:Unspecified(?)
Added in:1.30.0
Related Issues
View Source

crate_in_macro_def📋
suspiciouswarn

What it does

Checks for usage ofcrate as opposed to$crate in a macro definition.

Why is this bad?

crate refers to the macro call’s crate, whereas$crate refers to the macro definition’scrate. Rarely is the former intended. See:https://doc.rust-lang.org/reference/macros-by-example.html#hygiene

Example

#[macro_export]macro_rules! print_message {    () => {        println!("{}", crate::MESSAGE);    };}pub const MESSAGE: &str = "Hello!";

Use instead:

#[macro_export]macro_rules! print_message {    () => {        println!("{}", $crate::MESSAGE);    };}pub const MESSAGE: &str = "Hello!";

Note that if the use ofcrate is intentional, anallow attribute can be applied to themacro definition, e.g.:

#[allow(clippy::crate_in_macro_def)]macro_rules! ok { ... crate::foo ... }
Applicability:MachineApplicable(?)
Added in:1.62.0
Related Issues
View Source

create_dir📋
restrictionallow

What it does

Checks usage ofstd::fs::create_dir and suggest usingstd::fs::create_dir_all instead.

Why restrict this?

Sometimesstd::fs::create_dir is mistakenly chosen overstd::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

std::fs::create_dir("foo");

Use instead:

std::fs::create_dir_all("foo");
Applicability:MaybeIncorrect(?)
Added in:1.48.0
Related Issues
View Source

crosspointer_transmute📋
suspiciouswarn

What it does

Checks for transmutes between a typeT and*T.

Why is this bad?

It’s easy to mistakenly transmute between a type and apointer to that type.

Example

core::intrinsics::transmute(t) // where the result type is the same as                               // `*t` or `&t`'s
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

dbg_macro📋
restrictionallow

What it does

Checks for usage of thedbg! macro.

Why restrict this?

Thedbg! macro is intended as a debugging tool. It should not be present in releasedsoftware or committed to a version control system.

Example

dbg!(true)

Use instead:

true

Configuration

  • allow-dbg-in-tests: Whetherdbg! should be allowed in test functions or#[cfg(test)]

    (default:false)

Applicability:MachineApplicable(?)
Added in:1.34.0
Related Issues
View Source

debug_assert_with_mut_call📋
nurseryallow

What it does

Checks for function/method calls with a mutableparameter indebug_assert!,debug_assert_eq! anddebug_assert_ne! macros.

Why is this bad?

In release buildsdebug_assert! macros are optimized out by thecompiler.Therefore mutating something in adebug_assert! macro results in different behaviorbetween a release and debug build.

Example

debug_assert_eq!(vec![3].pop(), Some(3));// ordebug_assert!(takes_a_mut_parameter(&mut x));
Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

decimal_literal_representation📋
restrictionallow

What it does

Warns if there is a better representation for a numeric literal.

Why restrict this?

Especially for big powers of 2, a hexadecimal representation is usually morereadable than a decimal representation.

Example

`255` => `0xFF``65_535` => `0xFFFF``4_042_322_160` => `0xF0F0_F0F0`

Configuration

  • literal-representation-threshold: The lower bound for linting decimal literals

    (default:16384)

Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

declare_interior_mutable_const📋
suspiciouswarn

What it does

Checks for the declaration of named constant which contain interior mutability.

Why is this bad?

Named constants are copied at every use site which means any change to their valuewill be lost after the newly created value is dropped. e.g.

use core::sync::atomic::{AtomicUsize, Ordering};const ATOMIC: AtomicUsize = AtomicUsize::new(0);fn add_one() -> usize {    // This will always return `0` since `ATOMIC` is copied before it's used.    ATOMIC.fetch_add(1, Ordering::AcqRel)}

If shared modification of the value is desired, astatic item is needed instead.If that is not desired, aconst fn constructor should be used to make it obviousat the use site that a new value is created.

Known problems

Prior toconst fn stabilization this was the only way to provide a value whichcould initialize astatic item (e.g. thestd::sync::ONCE_INIT constant). Inthis case the use ofconst is required and this lint should be suppressed.

There also exists types which contain private fields with interior mutability, butno way to both create a value as a constant and modify any mutable field using thetype’s public interface (e.g.bytes::Bytes). As there is no reasonable way toscan a crate’s interface to see if this is the case, all such types will be linted.If this happens use theignore-interior-mutability configuration option to allowthe type.

Example

use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchangedassert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct

Use instead:

static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);STATIC_ATOM.store(9, SeqCst);assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance

Configuration

  • ignore-interior-mutability: A list of paths to types that should be treated as if they do not contain interior mutability

    (default:["bytes::Bytes"])

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

default_constructed_unit_structs📋
complexitywarn

What it does

Checks for construction on unit struct usingdefault.

Why is this bad?

This adds code complexity and an unnecessary function call.

Example

#[derive(Default)]struct S<T> {    _marker: PhantomData<T>}let _: S<i32> = S {    _marker: PhantomData::default()};

Use instead:

struct S<T> {    _marker: PhantomData<T>}let _: S<i32> = S {    _marker: PhantomData};
Applicability:MachineApplicable(?)
Added in:1.71.0
Related Issues
View Source

default_instead_of_iter_empty📋
stylewarn

What it does

It checks forstd::iter::Empty::default() and suggests replacing it withstd::iter::empty().

Why is this bad?

std::iter::empty() is the more idiomatic way.

Example

let _ = std::iter::Empty::<usize>::default();let iter: std::iter::Empty<usize> = std::iter::Empty::default();

Use instead:

let _ = std::iter::empty::<usize>();let iter: std::iter::Empty<usize> = std::iter::empty();
Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

default_numeric_fallback📋
restrictionallow

What it does

Checks for usage of unconstrained numeric literals which may cause default numeric fallback in typeinference.

Default numeric fallback means that if numeric types have not yet been bound to concretetypes at the end of type inference, then integer type is bound toi32, and similarlyfloating type is bound tof64.

SeeRFC0212 for more information about the fallback.

Why restrict this?

To ensure that every numeric type is chosen explicitly rather than implicitly.

Known problems

This lint is implemented using a custom algorithm independent of rustc’s inference,which results in many false positives and false negatives.

Example

let i = 10;let f = 1.23;

Use instead:

let i = 10_i32;let f = 1.23_f64;
Applicability:MaybeIncorrect(?)
Added in:1.52.0
Related Issues
View Source

default_trait_access📋
pedanticallow

What it does

Checks for literal calls toDefault::default().

Why is this bad?

It’s easier for the reader if the name of the type is used, rather than thegenericDefault.

Example

let s: String = Default::default();

Use instead:

let s = String::default();
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

default_union_representation📋
restrictionallow

What it does

Displays a warning when a union is declared with the default representation (without a#[repr(C)] attribute).

Why restrict this?

Unions in Rust have unspecified layout by default, despite many people thinking that theylay out each field at the start of the union (like C does). That is, there are no guaranteesabout the offset of the fields for unions with multiple non-ZST fields without an explicitlyspecified layout. These cases may lead to undefined behavior in unsafe blocks.

Example

union Foo {    a: i32,    b: u32,}fn main() {    let _x: u32 = unsafe {        Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding    };}

Use instead:

#[repr(C)]union Foo {    a: i32,    b: u32,}fn main() {    let _x: u32 = unsafe {        Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute    };}
Applicability:Unspecified(?)
Added in:1.60.0
Related Issues
View Source

deprecated_cfg_attr📋
complexitywarn

What it does

Checks for#[cfg_attr(rustfmt, rustfmt_skip)] and suggests to replace itwith#[rustfmt::skip].

Why is this bad?

Since tool_attributes (rust-lang/rust#44690)are stable now, they should be used instead of the oldcfg_attr(rustfmt) attributes.

Known problems

This lint doesn’t detect crate level inner attributes, because they getprocessed before the PreExpansionPass lints get executed. See#3123

Example

#[cfg_attr(rustfmt, rustfmt_skip)]fn main() { }

Use instead:

#[rustfmt::skip]fn main() { }

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.32.0
Related Issues
View Source

deprecated_clippy_cfg_attr📋
suspiciouswarn

What it does

Checks for#[cfg_attr(feature = "cargo-clippy", ...)] and for#[cfg(feature = "cargo-clippy")] and suggests to replace it with#[cfg_attr(clippy, ...)] or#[cfg(clippy)].

Why is this bad?

This feature has been deprecated for years and shouldn’t be used anymore.

Example

#[cfg(feature = "cargo-clippy")]struct Bar;

Use instead:

#[cfg(clippy)]struct Bar;
Applicability:MachineApplicable(?)
Added in:1.78.0
Related Issues
View Source

deprecated_semver📋
correctnessdeny

What it does

Checks for#[deprecated] annotations with asincefield that is not a valid semantic version. Also allows “TBD” to signalfuture deprecation.

Why is this bad?

For checking the version of the deprecation, it must bea valid semver. Failing that, the contained information is useless.

Example

#[deprecated(since = "forever")]fn something_else() { /* ... */ }
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

deref_addrof📋
complexitywarn

What it does

Checks for usage of*& and*&mut in expressions.

Why is this bad?

Immediately dereferencing a reference is no-op andmakes the code less clear.

Known problems

Multiple dereference/addrof pairs are not handled sothe suggested fix forx = **&&y isx = *&y, which is still incorrect.

Example

let a = f(*&mut b);let c = *&d;

Use instead:

let a = f(b);let c = d;
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

deref_by_slicing📋
restrictionallow

What it does

Checks for slicing expressions which are equivalent to dereferencing thevalue.

Why restrict this?

Some people may prefer to dereference rather than slice.

Example

let vec = vec![1, 2, 3];let slice = &vec[..];

Use instead:

let vec = vec![1, 2, 3];let slice = &*vec;
Applicability:MachineApplicable(?)
Added in:1.61.0
Related Issues
View Source

derivable_impls📋
complexitywarn

What it does

Detects manualstd::default::Default implementations that are identical to a derived implementation.

Why is this bad?

It is less concise.

Example

struct Foo {    bar: bool}impl Default for Foo {    fn default() -> Self {        Self {            bar: false        }    }}

Use instead:

#[derive(Default)]struct Foo {    bar: bool}

Known problems

Derive macrossometimes use incorrect boundsin generic types and the user definedimpl may be more generalized orspecialized than what derive will produce. This lint can’t detect the manualimplhas exactly equal bounds, and therefore this lint is disabled for types withgeneric parameters.

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.57.0
Related Issues
View Source

derive_ord_xor_partial_ord📋
correctnessdeny

What it does

Lints against manualPartialOrd andOrd implementations for types with a derivedOrdorPartialOrd implementation.

Why is this bad?

The implementation of these traits must agree (forexample for use withsort) so it’s probably a bad idea to use adefault-generatedOrd implementation with an explicitly definedPartialOrd. In particular, the following must hold for any typeimplementingOrd:

k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()

Example

#[derive(Ord, PartialEq, Eq)]struct Foo;impl PartialOrd for Foo {    ...}

Use instead:

#[derive(PartialEq, Eq)]struct Foo;impl PartialOrd for Foo {    fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {       Some(self.cmp(other))    }}impl Ord for Foo {    ...}

or, if you don’t need a custom ordering:

#[derive(Ord, PartialOrd, PartialEq, Eq)]struct Foo;
Applicability:Unspecified(?)
Added in:1.47.0
Related Issues
View Source

derive_partial_eq_without_eq📋
nurseryallow

What it does

Checks for types that derivePartialEq and could implementEq.

Why is this bad?

If a typeT derivesPartialEq and all of its members implementEq,thenT can always implementEq. ImplementingEq allowsT to be usedin APIs that requireEq types. It also allows structs containingT to deriveEq themselves.

Example

#[derive(PartialEq)]struct Foo {    i_am_eq: i32,    i_am_eq_too: Vec<String>,}

Use instead:

#[derive(PartialEq, Eq)]struct Foo {    i_am_eq: i32,    i_am_eq_too: Vec<String>,}
Applicability:MachineApplicable(?)
Added in:1.63.0
Related Issues
View Source

derived_hash_with_manual_eq📋
correctnessdeny

What it does

Lints against manualPartialEq implementations for types with a derivedHashimplementation.

Why is this bad?

The implementation of these traits must agree (forexample for use withHashMap) so it’s probably a bad idea to use adefault-generatedHash implementation with an explicitly definedPartialEq. In particular, the following must hold for any type:

k1 == k2 ⇒ hash(k1) == hash(k2)

Example

#[derive(Hash)]struct Foo;impl PartialEq for Foo {    ...}

Past names

  • derive_hash_xor_eq
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

disallowed_macros📋
stylewarn

What it does

Denies the configured macros in clippy.toml

Note: Even though this lint is warn-by-default, it will only trigger ifmacros are defined in the clippy.toml file.

Why is this bad?

Some macros are undesirable in certain contexts, and it’s beneficial tolint for them as needed.

Example

An example clippy.toml configuration:

disallowed-macros = [    # Can use a string as the path of the disallowed macro.    "std::print",    # Can also use an inline table with a `path` key.    { path = "std::println" },    # When using an inline table, can add a `reason` for why the macro    # is disallowed.    { path = "serde::Serialize", reason = "no serializing" },    # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,    # it will be silently ignored    { path = "std::invalid_macro", reason = "use alternative instead", allow-invalid = true }]
use serde::Serialize;println!("warns");// The diagnostic will contain the message "no serializing"#[derive(Serialize)]struct Data {    name: String,    value: usize,}

Configuration

  • disallowed-macros: The list of disallowed macros, written as fully qualified paths.

Fields:

  • path (required): the fully qualified path to the macro that should be disallowed

  • reason (optional): explanation why this macro is disallowed

  • replacement (optional): suggested alternative macro

  • allow-invalid (optional,false by default): when set totrue, it will ignore this entryif the path doesn’t exist, instead of emitting an error

    (default:[])

Applicability:Unspecified(?)
Added in:1.66.0
Related Issues
View Source

disallowed_methods📋
stylewarn

What it does

Denies the configured methods and functions in clippy.toml

Note: Even though this lint is warn-by-default, it will only trigger ifmethods are defined in the clippy.toml file.

Why is this bad?

Some methods are undesirable in certain contexts, and it’s beneficial tolint for them as needed.

Example

An example clippy.toml configuration:

disallowed-methods = [    # Can use a string as the path of the disallowed method.    "std::boxed::Box::new",    # Can also use an inline table with a `path` key.    { path = "std::time::Instant::now" },    # When using an inline table, can add a `reason` for why the method    # is disallowed.    { path = "std::vec::Vec::leak", reason = "no leaking memory" },    # Can also add a `replacement` that will be offered as a suggestion.    { path = "std::sync::Mutex::new", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex::new" },    # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,    # it will be silently ignored    { path = "std::fs::InvalidPath", reason = "use alternative instead", allow-invalid = true },]
let xs = vec![1, 2, 3, 4];xs.leak(); // Vec::leak is disallowed in the config.// The diagnostic contains the message "no leaking memory".let _now = Instant::now(); // Instant::now is disallowed in the config.let _box = Box::new(3); // Box::new is disallowed in the config.

Use instead:

let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.xs.push(123); // Vec::push is _not_ disallowed in the config.

Past names

  • disallowed_method

Configuration

  • disallowed-methods: The list of disallowed methods, written as fully qualified paths.

Fields:

  • path (required): the fully qualified path to the method that should be disallowed

  • reason (optional): explanation why this method is disallowed

  • replacement (optional): suggested alternative method

  • allow-invalid (optional,false by default): when set totrue, it will ignore this entryif the path doesn’t exist, instead of emitting an error

    (default:[])

Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

disallowed_names📋
stylewarn

What it does

Checks for usage of disallowed names for variables, suchasfoo.

Why is this bad?

These names are usually placeholder names and should beavoided.

Example

let foo = 3.14;

Past names

  • blacklisted_name

Configuration

  • disallowed-names: The list of disallowed names to lint about. NB:bar is not here since it has legitimate uses. The value".." can be used as part of the list to indicate that the configured values should be appended to thedefault configuration of Clippy. By default, any configuration will replace the default value.

    (default:["foo", "baz", "quux"])

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

disallowed_script_idents📋
restrictionallow

What it does

Checks for usage of unicode scripts other than those explicitly allowedby the lint config.

This lint doesn’t take into account non-text scripts such asUnknown andLinear_A.It also ignores theCommon script type.While configuring, be sure to use official script namealiases fromthe list of supported scripts.

See also:non_ascii_idents.

Why restrict this?

It may be not desired to have many different scripts foridentifiers in the codebase.

Note that if you only want to allow typical English, you might want to usebuilt-innon_ascii_idents lint instead.

Example

// Assuming that `clippy.toml` contains the following line:// allowed-scripts = ["Latin", "Cyrillic"]let counter = 10; // OK, latin is allowed.let счётчик = 10; // OK, cyrillic is allowed.let zähler = 10; // OK, it's still latin.let カウンタ = 10; // Will spawn the lint.

Configuration

  • allowed-scripts: The list of unicode scripts allowed to be used in the scope.

    (default:["Latin"])

Applicability:Unspecified(?)
Added in:1.55.0
Related Issues
View Source

disallowed_types📋
stylewarn

What it does

Denies the configured types in clippy.toml.

Note: Even though this lint is warn-by-default, it will only trigger iftypes are defined in the clippy.toml file.

Why is this bad?

Some types are undesirable in certain contexts.

Example:

An example clippy.toml configuration:

disallowed-types = [    # Can use a string as the path of the disallowed type.    "std::collections::BTreeMap",    # Can also use an inline table with a `path` key.    { path = "std::net::TcpListener" },    # When using an inline table, can add a `reason` for why the type    # is disallowed.    { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },    # Can also add a `replacement` that will be offered as a suggestion.    { path = "std::sync::Mutex", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex" },    # This would normally error if the path is incorrect, but with `allow-invalid` = `true`,    # it will be silently ignored    { path = "std::invalid::Type", reason = "use alternative instead", allow-invalid = true }]
use std::collections::BTreeMap;// or its uselet x = std::collections::BTreeMap::new();

Use instead:

// A similar type that is allowed by the configuse std::collections::HashMap;

Past names

  • disallowed_type

Configuration

  • disallowed-types: The list of disallowed types, written as fully qualified paths.

Fields:

  • path (required): the fully qualified path to the type that should be disallowed

  • reason (optional): explanation why this type is disallowed

  • replacement (optional): suggested alternative type

  • allow-invalid (optional,false by default): when set totrue, it will ignore this entryif the path doesn’t exist, instead of emitting an error

    (default:[])

Applicability:MachineApplicable(?)
Added in:1.55.0
Related Issues
View Source

diverging_sub_expression📋
complexitywarn

What it does

Checks for diverging calls that are not match arms orstatements.

Why is this bad?

It is often confusing to read. In addition, thesub-expression evaluation order for Rust is not well documented.

Known problems

Someone might want to usesome_bool || panic!() as ashorthand.

Example

let a = b() || panic!() || c();// `c()` is dead, `panic!()` is only called if `b()` returns `false`let x = (a, b, c, panic!());// can simply be replaced by `panic!()`
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

doc_broken_link📋
pedanticallow

What it does

Checks the doc comments have unbroken links, mostly causedby bad formatted links such as broken across multiple lines.

Why is this bad?

Because documentation generated by rustdoc will be brokensince expected links won’t be links and just text.

Examples

This link is broken:

/// [example of a bad link](https:///// github.com/rust-lang/rust-clippy/)pub fn do_something() {}

It shouldn’t be broken across multiple lines to work:

/// [example of a good link](https://github.com/rust-lang/rust-clippy/)pub fn do_something() {}
Applicability:Unspecified(?)
Added in:1.90.0
Related Issues
View Source

doc_comment_double_space_linebreaks📋
pedanticallow

What it does

Detects doc comment linebreaks that use double spaces to separate lines, instead of back-slash (\).

Why is this bad?

Double spaces, when used as doc comment linebreaks, can be difficult to see, and mayaccidentally be removed during automatic formatting or manual refactoring. The use of a back-slash (\)is clearer in this regard.

Example

The two replacement dots in this example represent a double space.

/// This command takes two numbers as inputs and··/// adds them together, and then returns the result.fn add(l: i32, r: i32) -> i32 {    l + r}

Use instead:

/// This command takes two numbers as inputs and\/// adds them together, and then returns the result.fn add(l: i32, r: i32) -> i32 {    l + r}
Applicability:MachineApplicable(?)
Added in:1.87.0
Related Issues
View Source

doc_include_without_cfg📋
restrictionallow

What it does

Checks if included files in doc comments are included only forcfg(doc).

Why restrict this?

These files are not useful for compilation but will still be included.Also, if any of these non-source code file is updated, it will trigger arecompilation.

Known problems

Excluding this will currently result in the file being left out ifthe item’s docs are inlined from another crate. This may be fixed in afuture version of rustdoc.

Example

#![doc = include_str!("some_file.md")]

Use instead:

#![cfg_attr(doc, doc = include_str!("some_file.md"))]
Applicability:MachineApplicable(?)
Added in:1.85.0
Related Issues
View Source

doc_lazy_continuation📋
stylewarn

What it does

In CommonMark Markdown, the language used to write doc comments, aparagraph nested within a list or block quote does not need any lineafter the first one to be indented or marked. The specification callsthis a “lazy paragraph continuation.”

Why is this bad?

This is easy to write but hard to read. Lazy continuations makesunintended markers hard to see, and make it harder to deduce thedocument’s intended structure.

Example

This table is probably intended to have two rows,but it does not. It has zero rows, and is followed bya block quote.

/// Range | Description/// ----- | -----------/// >= 1  | fully opaque/// < 1   | partially see-throughfn set_opacity(opacity: f32) {}

Fix it by escaping the marker:

/// Range | Description/// ----- | -----------/// \>= 1 | fully opaque/// < 1   | partially see-throughfn set_opacity(opacity: f32) {}

This example is actually intended to be a list:

/// * Do nothing./// * Then do something. Whatever it is needs done,/// it should be done right now.

Fix it by indenting the list contents:

/// * Do nothing./// * Then do something. Whatever it is needs done,///   it should be done right now.
Applicability:MachineApplicable(?)
Added in:1.80.0
Related Issues
View Source

doc_link_code📋
nurseryallow

What it does

Checks for links with code directly adjacent to code text:[`MyItem`]`<`[`u32`]`>`.

Why is this bad?

It can be written more simply using HTML-style<code> tags.

Example

//! [`first`](x)`second`

Use instead:

//! <code>[first](x)second</code>
Applicability:MaybeIncorrect(?)
Added in:1.87.0
Related Issues
View Source

doc_link_with_quotes📋
pedanticallow

What it does

Detects the syntax['foo'] in documentation comments (notice quotes instead of backticks)outside of code blocks

Why is this bad?

It is likely a typo when defining an intra-doc link

Example

/// See also: ['foo']fn bar() {}

Use instead:

/// See also: [`foo`]fn bar() {}
Applicability:Unspecified(?)
Added in:1.63.0
Related Issues
View Source

doc_markdown📋
pedanticallow

What it does

Checks for the presence of_,:: or camel-case wordsoutside ticks in documentation.

Why is this bad?

Rustdoc supports markdown formatting,_,:: andcamel-case probably indicates some code which should be included betweenticks._ can also be used for emphasis in markdown, this lint tries toconsider that.

Known problems

Lots of bad docs won’t be fixed, what the lint checksfor is limited, and there are still false positives. HTML elements and theircontent are not linted.

In addition, when writing documentation comments, including[] bracketsinside a link text would trip the parser. Therefore, documenting link with[SmallVec<[T; INLINE_CAPACITY]>] and then [SmallVec<[T; INLINE_CAPACITY]>]: SmallVecwould fail.

Examples

/// Do something with the foo_bar parameter. See also/// that::other::module::foo.// ^ `foo_bar` and `that::other::module::foo` should be ticked.fn doit(foo_bar: usize) {}
// Link text with `[]` brackets should be written as following:/// Consume the array and return the inner/// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec]./// [SmallVec]: SmallVecfn main() {}

Configuration

  • doc-valid-idents: The list of words this lint should not consider as identifiers needing ticks. The value".." can be used as part of the list to indicate, that the configured values should be appended to thedefault configuration of Clippy. By default, any configuration will replace the default value. For example:
  • doc-valid-idents = ["ClipPy"] would replace the default list with["ClipPy"].

  • doc-valid-idents = ["ClipPy", ".."] would appendClipPy to the default list.

    (default:["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "InfiniBand", "RoCE", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"])

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

doc_nested_refdefs📋
suspiciouswarn

What it does

Warns if a link reference definition appears at the start of alist item or quote.

Why is this bad?

This is probably intended as an intra-doc link. If it is reallysupposed to be a reference definition, it can be written outsideof the list item or quote.

Example

//! - [link]: description

Use instead:

//! - [link][]: description (for intra-doc link)//!//! [link]: destination (for link reference definition)
Applicability:MaybeIncorrect(?)
Added in:1.85.0
Related Issues
View Source

doc_overindented_list_items📋
stylewarn

What it does

Detects overindented list items in doc comments where the continuationlines are indented more than necessary.

Why is this bad?

Overindented list items in doc comments can lead to inconsistent andpoorly formatted documentation when rendered. Excessive indentation maycause the text to be misinterpreted as a nested list item or code block,affecting readability and the overall structure of the documentation.

Example

/// - This is the first item in a list///      and this line is overindented.

Fixes this into:

/// - This is the first item in a list///   and this line is overindented.
Applicability:MaybeIncorrect(?)
Added in:1.86.0
Related Issues
View Source

doc_suspicious_footnotes📋
suspiciouswarn

What it does

Detects syntax that looks like a footnote reference.

Rustdoc footnotes are compatible with GitHub-Flavored Markdown (GFM).GFM does not parse a footnote reference unless its definition alsoexists. This lint checks for footnote references with missingdefinitions, unless it thinks you’re writing a regex.

Why is this bad?

This probably means that a footnote was meant to exist,but was not written.

Example

/// This is not a footnote[^1], because no definition exists.fn my_fn() {}

Use instead:

/// This is a footnote[^1].////// [^1]: defined herefn my_fn() {}
Applicability:HasPlaceholders(?)
Added in:1.89.0
Related Issues
View Source

double_comparisons📋
complexitywarn

What it does

Checks for double comparisons that could be simplified to a single expression.

Why is this bad?

Readability.

Example

if x == y || x < y {}

Use instead:

if x <= y {}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

double_ended_iterator_last📋
perfwarn

What it does

Checks forIterator::last being called on aDoubleEndedIterator, which can be replacedwithDoubleEndedIterator::next_back.

Why is this bad?

Iterator::last is implemented by consuming the iterator, which is unnecessary ifthe iterator is aDoubleEndedIterator. Since Rust traits do not allow specialization,Iterator::last cannot be optimized forDoubleEndedIterator.

Example

let last_arg = "echo hello world".split(' ').last();

Use instead:

let last_arg = "echo hello world".split(' ').next_back();
Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

double_must_use📋
stylewarn

What it does

Checks for a#[must_use] attribute withoutfurther information on functions and methods that return a type alreadymarked as#[must_use].

Why is this bad?

The attribute isn’t needed. Not using the resultwill already be reported. Alternatively, one can add some text to theattribute to improve the lint message.

Examples

#[must_use]fn double_must_use() -> Result<(), ()> {    unimplemented!();}
Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

double_parens📋
complexitywarn

What it does

Checks for unnecessary double parentheses.

Why is this bad?

This makes code harder to read and might indicate amistake.

Example

fn simple_double_parens() -> i32 {    ((0))}foo((0));

Use instead:

fn simple_no_parens() -> i32 {    (0)}foo(0);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

drain_collect📋
perfwarn

What it does

Checks for calls to.drain() that clear the collection, immediately followed by a call to.collect().

“Collection” in this context refers to any type with adrain method:Vec,VecDeque,BinaryHeap,HashSet,HashMap,String

Why is this bad?

Usingmem::take is faster as it avoids the allocation.When usingmem::take, the old collection is replaced with an empty one and ownership ofthe old collection is returned.

Known issues

mem::take(&mut vec) is almost equivalent tovec.drain(..).collect(), except thatit also moves thecapacity. The user might have explicitly written it this wayto keep the capacity on the originalVec.

Example

fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {    v.drain(..).collect()}

Use instead:

use std::mem;fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {    mem::take(v)}
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

drop_non_drop📋
suspiciouswarn

What it does

Checks for calls tostd::mem::drop with a value that does not implementDrop.

Why is this bad?

Callingstd::mem::drop is no different than dropping such a type. A different value mayhave been intended.

Example

struct Foo;let x = Foo;std::mem::drop(x);
Applicability:Unspecified(?)
Added in:1.62.0
Related Issues
View Source

duplicate_mod📋
suspiciouswarn

What it does

Checks for files that are included as modules multiple times.

Why is this bad?

Loading a file as a module more than once causes it to be compiledmultiple times, taking longer and putting duplicate content into themodule tree.

Example

// lib.rsmod a;mod b;
// a.rs#[path = "./b.rs"]mod b;

Use instead:

// lib.rsmod a;mod b;
// a.rsuse crate::b;
Applicability:Unspecified(?)
Added in:1.63.0
Related Issues
View Source

duplicate_underscore_argument📋
stylewarn

What it does

Checks for function arguments having the similar namesdiffering by an underscore.

Why is this bad?

It affects code readability.

Example

fn foo(a: i32, _a: i32) {}

Use instead:

fn bar(a: i32, _b: i32) {}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

duplicated_attributes📋
suspiciouswarn

What it does

Checks for attributes that appear two or more times.

Why is this bad?

Repeating an attribute on the same item (or globally on the same crate)is unnecessary and doesn’t have an effect.

Example

#[allow(dead_code)]#[allow(dead_code)]fn foo() {}

Use instead:

#[allow(dead_code)]fn foo() {}
Applicability:Unspecified(?)
Added in:1.79.0
Related Issues
View Source

duration_subsec📋
complexitywarn

What it does

Checks for calculation of subsecond microseconds or millisecondsfrom otherDuration methods.

Why is this bad?

It’s more concise to callDuration::subsec_micros() orDuration::subsec_millis() than to calculate them.

Example

let micros = duration.subsec_nanos() / 1_000;let millis = duration.subsec_nanos() / 1_000_000;

Use instead:

let micros = duration.subsec_micros();let millis = duration.subsec_millis();
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

eager_transmute📋
correctnessdeny

What it does

Checks for integer validity checks, followed by a transmute that is (incorrectly) evaluatedeagerly (e.g. usingbool::then_some).

Why is this bad?

Eager evaluation means that thetransmute call is executed regardless of whether the condition is true or false.This can introduce unsoundness and other subtle bugs.

Example

Consider the following function which is meant to convert an unsigned integer to its enum equivalent via transmute.

#[repr(u8)]enum Opcode {    Add = 0,    Sub = 1,    Mul = 2,    Div = 3}fn int_to_opcode(op: u8) -> Option<Opcode> {    (op < 4).then_some(unsafe { std::mem::transmute(op) })}

This may appear fine at first given that it checks that theu8 is within the validity range of the enum,however the transmute is evaluated eagerly, meaning that it executes even ifop >= 4!

This makes the function unsound, because it is possible for the caller to cause undefined behavior(creating an enum with an invalid bitpattern) entirely in safe code only by passing an incorrect value,which is normally only a bug that is possible in unsafe code.

One possible way in which this can go wrong practically is that the compiler sees it as:

let temp: Foo = unsafe { std::mem::transmute(op) };(0 < 4).then_some(temp)

and optimizes away the(0 < 4) check based on the assumption that since aFoo was created fromop with the validity range0..3,it isimpossible for this condition to be false.

In short, it is possible for this function to be optimized in a way that makes itnever returnNone,even if passed the value4.

This can be avoided by instead using lazy evaluation. For the example above, this should be written:

fn int_to_opcode(op: u8) -> Option<Opcode> {    (op < 4).then(|| unsafe { std::mem::transmute(op) })             ^^^^ ^^ `bool::then` only executes the closure if the condition is true!}
Applicability:MaybeIncorrect(?)
Added in:1.77.0
Related Issues
View Source

elidable_lifetime_names📋
pedanticallow

What it does

Checks for lifetime annotations which can be replaced with anonymous lifetimes ('_).

Why is this bad?

The additional lifetimes can make the code look more complicated.

Known problems

This lint ignores functions withwhere clauses that referencelifetimes to prevent false positives.

Example

fn f<'a>(x: &'a str) -> Chars<'a> {    x.chars()}

Use instead:

fn f(x: &str) -> Chars<'_> {    x.chars()}
Applicability:MachineApplicable(?)
Added in:1.87.0
Related Issues
View Source

else_if_without_else📋
restrictionallow

What it does

Checks for usage of if expressions with anelse if branch,but without a finalelse branch.

Why restrict this?

Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10).

Example

if x.is_positive() {    a();} else if x.is_negative() {    b();}

Use instead:

if x.is_positive() {    a();} else if x.is_negative() {    b();} else {    // We don't care about zero.}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

empty_docs📋
suspiciouswarn

What it does

Detects documentation that is empty.

Why is this bad?

Empty docs clutter code without adding value, reducing readability and maintainability.

Example

///fn returns_true() -> bool {    true}

Use instead:

fn returns_true() -> bool {    true}
Applicability:Unspecified(?)
Added in:1.78.0
Related Issues
View Source

empty_drop📋
restrictionallow

What it does

Checks for emptyDrop implementations.

Why restrict this?

EmptyDrop implementations have no effect when dropping an instance of the type. They aremost likely useless. However, an emptyDrop implementation prevents a type from beingdestructured, which might be the intention behind adding the implementation as a marker.

Example

struct S;impl Drop for S {    fn drop(&mut self) {}}

Use instead:

struct S;
Applicability:MaybeIncorrect(?)
Added in:1.62.0
Related Issues
View Source

empty_enum_variants_with_brackets📋
restrictionallow

What it does

Finds enum variants without fields that are declared with empty brackets.

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 API change, and adding them backis abreaking API change.

Example

enum MyEnum {    HasData(u8),    HasNoData(),       // redundant parentheses    NoneHereEither {}, // redundant braces}

Use instead:

enum MyEnum {    HasData(u8),    HasNoData,    NoneHereEither,}
Applicability:MaybeIncorrect(?)
Added in:1.77.0
Related Issues
View Source

empty_enums📋
pedanticallow

What it does

Checks forenums with no variants, which therefore are uninhabited types(cannot be instantiated).

As of this writing, thenever_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 only want a type which can’t 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 anewtypestructcontaining! instead (struct MyType(pub !)), because it is more idiomaticto use astruct rather than anenum when anenum is unnecessary.

    If you do this, note that thevisibility of the! field determines whetherthe uninhabitedness is visible in documentation, and whether it can be patternmatched to mark code unreachable. If the field is not visible, then the structacts like any other struct with private fields.

For further information, visitthe never type’s documentation.

Example

enum CannotExist {}

Use instead:

#![feature(never_type)]/// Use the `!` type directly...type CannotExist = !;/// ...or define a newtype which is distinct.struct CannotExist2(pub !);

Past names

  • empty_enum
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

empty_line_after_doc_comments📋
suspiciouswarn

What it does

Checks for empty lines after doc comments.

Why is this bad?

The doc comment may have meant to be an inner doc comment, regularcomment or applied to some old code that is now commented out. If it wasintended to be a doc comment, then the empty line should be removed.

Example

/// Some doc comment with a blank line after it.fn f() {}/// Docs for `old_code`// fn old_code() {}fn new_code() {}

Use instead:

//! Convert it to an inner doc comment// Or a regular comment/// Or remove the empty linefn f() {}// /// Docs for `old_code`// fn old_code() {}fn new_code() {}
Applicability:MaybeIncorrect(?)
Added in:1.70.0
Related Issues
View Source

empty_line_after_outer_attr📋
suspiciouswarn

What it does

Checks for empty lines after outer attributes

Why is this bad?

The attribute may have meant to be an inner attribute (#![attr]). Ifit was meant to be an outer attribute (#[attr]) then the empty lineshould be removed

Example

#[allow(dead_code)]fn not_quite_good_code() {}

Use instead:

// Good (as inner attribute)#![allow(dead_code)]fn this_is_fine() {}// or// Good (as outer attribute)#[allow(dead_code)]fn this_is_fine_too() {}
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

empty_loop📋
suspiciouswarn

What it does

Checks for emptyloop expressions.

Why is this bad?

These busy loops burn CPU cycles without doinganything. It isalmost always a better idea topanic! than to havea busy loop.

If panicking isn’t possible, think of the environment and either:

  • block on something
  • sleep the thread for some microseconds
  • yield or pause the thread

Forstd targets, this can be done withstd::thread::sleeporstd::thread::yield_now.

Forno_std targets, doing this is more complicated, especially because#[panic_handler]s can’t panic. To stop/pause the thread, you willprobably need to invoke some target-specific intrinsic. Examples include:

Example

loop {}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

empty_structs_with_brackets📋
restrictionallow

What it does

Finds structs without fields (a so-called “empty struct”) that are declared with brackets.

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 API change, and adding them backis abreaking API change.

Example

struct Cookie {}struct Biscuit();

Use instead:

struct Cookie;struct Biscuit;
Applicability:Unspecified(?)
Added in:1.62.0
Related Issues
View Source

enum_clike_unportable_variant📋
correctnessdeny

What it does

Checks for C-like enumerations that arerepr(isize/usize) and have values that don’t fit into ani32.

Why is this bad?

This will truncate the variant value on 32 bitarchitectures, but works fine on 64 bit.

Example

#[repr(usize)]enum NonPortable {    X = 0x1_0000_0000,    Y = 0,}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

enum_glob_use📋
pedanticallow

What it does

Checks foruse Enum::*.

Why is this bad?

It is usually better style to use the prefixed name ofan enumeration variant, rather than importing variants.

Known problems

Old-style enumerations that prefix the variants arestill around.

Example

use std::cmp::Ordering::*;foo(Less);

Use instead:

use std::cmp::Ordering;foo(Ordering::Less)
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

enum_variant_names📋
stylewarn

What it does

Detects enumeration variants that are prefixed or suffixedby the same characters.

Why is this bad?

Enumeration variant names should specify their variant,not repeat the enumeration name.

Limitations

Characters with no casing will be considered when comparing prefixes/suffixesThis applies to numbers and non-ascii characters without casinge.g.Foo1 andFoo2 is considered to have different prefixes(the prefixes areFoo1 andFoo2 respectively), as alsoBar螃,Bar蟹

Example

enum Cake {    BlackForestCake,    HummingbirdCake,    BattenbergCake,}

Use instead:

enum Cake {    BlackForest,    Hummingbird,    Battenberg,}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

  • enum-variant-name-threshold: The minimum number of enum variants for the lints about variant names to trigger

    (default:3)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

eq_op📋
correctnessdeny

What it does

Checks for equal operands to comparison, logical andbitwise, difference and division binary operators (==,>, etc.,&&,||,&,|,^,- and/).

Why is this bad?

This is usually just a typo or a copy and paste error.

Known problems

False negatives: We had some false positives regardingcalls (notablyracer had one instanceofx.pop() && x.pop()), so we removed matching any function or methodcalls. We may introduce a list of known pure functions in the future.

Example

if x + 1 == x + 1 {}// orassert_eq!(a, a);
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

equatable_if_let📋
nurseryallow

What it does

Checks for pattern matchings that can be expressed using equality.

Why is this bad?

  • It reads better and has less cognitive load because equality won’t cause binding.
  • It is aYoda condition. Yoda conditions are widelycriticized for increasing the cognitive load of reading the code.
  • Equality is a simple bool expression and can be merged with&& and|| andreuse if blocks

Example

if let Some(2) = x {    do_thing();}

Use instead:

if x == Some(2) {    do_thing();}
Applicability:MachineApplicable(?)
Added in:1.57.0
Related Issues
View Source

erasing_op📋
correctnessdeny

What it does

Checks for erasing operations, e.g.,x * 0.

Why is this bad?

The whole expression can be replaced by zero.This is most likely not the intended outcome and should probably becorrected

Example

let x = 1;0 / x;0 * x;x & 0;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

err_expect📋
stylewarn

What it does

Checks for.err().expect() calls on theResult type.

Why is this bad?

.expect_err() can be called directly to avoid the extra type conversion fromerr().

Example

let x: Result<u32, &str> = Ok(10);x.err().expect("Testing err().expect()");

Use instead:

let x: Result<u32, &str> = Ok(10);x.expect_err("Testing expect_err");

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.62.0
Related Issues
View Source

error_impl_error📋
restrictionallow

What it does

Checks for types namedError that implementError.

Why restrict this?

It can become confusing when a codebase has 20 types all namedError, requiring eitheraliasing them in theuse statement or qualifying them likemy_module::Error. Thishinders comprehension, as it requires you to memorize every variation of importingErrorused across a codebase.

Example

#[derive(Debug)]pub enum Error { ... }impl std::fmt::Display for Error { ... }impl std::error::Error for Error { ... }
Applicability:Unspecified(?)
Added in:1.73.0
Related Issues
View Source

excessive_nesting📋
complexitywarn

What it does

Checks for blocks which are nested beyond a certain threshold.

Note: Even though this lint is warn-by-default, it will only trigger if a maximum nesting level is defined in the clippy.toml file.

Why is this bad?

It can severely hinder readability.

Example

An example clippy.toml configuration:

excessive-nesting-threshold = 3
// lib.rspub mod a {    pub struct X;    impl X {        pub fn run(&self) {            if true {                // etc...            }        }    }}

Use instead:

// a.rsfn private_run(x: &X) {    if true {        // etc...    }}pub struct X;impl X {    pub fn run(&self) {        private_run(self);    }}
// lib.rspub mod a;

Configuration

  • excessive-nesting-threshold: The maximum amount of nesting a block can reside in

    (default:0)

Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

excessive_precision📋
stylewarn

What it does

Checks for float literals with a precision greaterthan that supported by the underlying type.

The lint is suppressed for literals with overconst_literal_digits_threshold digits.

Why is this bad?

Rust will truncate the literal silently.

Example

let v: f32 = 0.123_456_789_9;println!("{}", v); //  0.123_456_789

Use instead:

let v: f64 = 0.123_456_789_9;println!("{}", v); //  0.123_456_789_9

Configuration

  • const-literal-digits-threshold: The minimum digits a const float literal must have to supress theexcessive_precicion lint

    (default:30)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

exhaustive_enums📋
restrictionallow

What it does

Warns on any exportedenums that are not tagged#[non_exhaustive]

Why restrict this?

Making anenum 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 exhaustiveenum is explicitly#[allow]ed.

Example

enum Foo {    Bar,    Baz}

Use instead:

#[non_exhaustive]enum Foo {    Bar,    Baz}
Applicability:MaybeIncorrect(?)
Added in:1.51.0
Related Issues
View Source

exhaustive_structs📋
restrictionallow

What it does

Warns on any exportedstructs that are not tagged#[non_exhaustive]

Why restrict this?

Making astruct 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 exhaustivestruct is explicitly#[allow]ed.

Example

struct Foo {    bar: u8,    baz: String,}

Use instead:

#[non_exhaustive]struct Foo {    bar: u8,    baz: String,}
Applicability:MaybeIncorrect(?)
Added in:1.51.0
Related Issues
View Source

exit📋
restrictionallow

What it does

Detects calls to theexit() function that are not in themain function. Calls toexit()immediately terminate the program.

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 callingexit() frommain() (which is a single place to look).

Good example

fn main() {    std::process::exit(0);}

Bad example

fn main() {    other_function();}fn other_function() {    std::process::exit(0);}

Use instead:

// To provide a stacktrace and additional informationpanic!("message");// or a main method with a returnfn main() -> Result<(), i32> {    Ok(())}
Applicability:Unspecified(?)
Added in:1.41.0
Related Issues
View Source

expect_fun_call📋
perfwarn

What it does

Checks for calls to.expect(&format!(...)),.expect(foo(..)),etc., and suggests to useunwrap_or_else instead

Why is this bad?

The function will always be called.

Known problems

If the function has side-effects, not calling it willchange the semantics of the program, but you shouldn’t rely on that anyway.

Example

foo.expect(&format!("Err {}: {}", err_code, err_msg));// orfoo.expect(format!("Err {}: {}", err_code, err_msg).as_str());

Use instead:

foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

expect_used📋
restrictionallow

What it does

Checks for.expect() or.expect_err() calls onResults and.expect() call onOptions.

Why restrict this?

Usually it is better to handle theNone orErr case.Still, for a lot of quick-and-dirty code,expect is a good choice, which is whythis lint isAllow by default.

result.expect() will let the thread panic onErrvalues. Normally, you want to implement more sophisticated error handling,and propagate errors upwards with? operator.

Examples

option.expect("one");result.expect("one");

Use instead:

option?;// orresult?;

Past names

  • option_expect_used
  • result_expect_used

Configuration

  • allow-expect-in-consts: Whetherexpect should be allowed in code always evaluated at compile time

    (default:true)

  • allow-expect-in-tests: Whetherexpect should be allowed in test functions or#[cfg(test)]

    (default:false)

Applicability:Unspecified(?)
Added in:1.45.0
Related Issues
View Source

expl_impl_clone_on_copy📋
pedanticallow

What it does

Checks for explicitClone implementations forCopytypes.

Why is this bad?

To avoid surprising behavior, these traits shouldagree and the behavior ofCopy cannot be overridden. In almost allsituations aCopy type should have aClone implementation that doesnothing more than copy the object, which is what#[derive(Copy, Clone)]gets you.

Example

#[derive(Copy)]struct Foo;impl Clone for Foo {    // ..}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

explicit_auto_deref📋
complexitywarn

What it does

Checks for dereferencing expressions which would be covered by auto-deref.

Why is this bad?

This unnecessarily complicates the code.

Example

let x = String::new();let y: &str = &*x;

Use instead:

let x = String::new();let y: &str = &x;
Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

explicit_counter_loop📋
complexitywarn

What it does

Checksfor loops over slices with an explicit counterand suggests the use of.enumerate().

Why is this bad?

Using.enumerate() makes the intent more clear,declutters the code and may be faster in some instances.

Example

let mut i = 0;for item in &v {    bar(i, *item);    i += 1;}

Use instead:

for (i, item) in v.iter().enumerate() { bar(i, *item); }
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

explicit_deref_methods📋
pedanticallow

What it does

Checks for explicitderef() orderef_mut() method calls.

Why is this bad?

Dereferencing by&*x or&mut *x is clearer and more concise,when not part of a method chain.

Example

use std::ops::Deref;let a: &mut String = &mut String::from("foo");let b: &str = a.deref();

Use instead:

let a: &mut String = &mut String::from("foo");let b = &*a;

This lint excludes all of:

let _ = d.unwrap().deref();let _ = Foo::deref(&foo);let _ = <Foo as Deref>::deref(&foo);
Applicability:MachineApplicable(?)
Added in:1.44.0
Related Issues
View Source

explicit_into_iter_loop📋
pedanticallow

What it does

Checks for loops ony.into_iter() wherey will do, andsuggests the latter.

Why is this bad?

Readability.

Example

// with `y` a `Vec` or slice:for x in y.into_iter() {    // ..}

can be rewritten to

for x in y {    // ..}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

explicit_iter_loop📋
pedanticallow

What it does

Checks for loops onx.iter() where&x will do, andsuggests the latter.

Why is this bad?

Readability.

Known problems

False negatives. We currently only warn on some knowntypes.

Example

// with `y` a `Vec` or slice:for x in y.iter() {    // ..}

Use instead:

for x in &y {    // ..}

Configuration

  • enforce-iter-loop-reborrow: Whether to recommend using implicit into iter for reborrowed values.

Example

let mut vec = vec![1, 2, 3];let rmvec = &mut vec;for _ in rmvec.iter() {}for _ in rmvec.iter_mut() {}

Use instead:

let mut vec = vec![1, 2, 3];let rmvec = &mut vec;for _ in &*rmvec {}for _ in &mut *rmvec {}

(default:false)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

explicit_write📋
complexitywarn

What it does

Checks for usage ofwrite!() /writeln()! which can bereplaced with(e)print!() /(e)println!()

Why is this bad?

Using(e)println! is clearer and more concise

Example

writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();writeln!(&mut std::io::stdout(), "foo: {:?}", bar).unwrap();

Use instead:

eprintln!("foo: {:?}", bar);println!("foo: {:?}", bar);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

extend_from_slice📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

Vec::extend_from_slice is no longer faster thanVec::extend due to specialization.

Applicability:Unspecified(?)
Deprecated in:pre 1.29.0
Related Issues

extend_with_drain📋
perfwarn

What it does

Checks for occurrences where one vector gets extended instead of append

Why is this bad?

Usingappend instead ofextend is more concise and faster

Example

let mut a = vec![1, 2, 3];let mut b = vec![4, 5, 6];a.extend(b.drain(..));

Use instead:

let mut a = vec![1, 2, 3];let mut b = vec![4, 5, 6];a.append(&mut b);
Applicability:MachineApplicable(?)
Added in:1.55.0
Related Issues
View Source

extra_unused_lifetimes📋
complexitywarn

What it does

Checks for lifetimes in generics that are never usedanywhere else.

Why is this bad?

The additional lifetimes make the code look morecomplicated, while there is nothing out of the ordinary going on. Removingthem leads to more readable code.

Example

// unnecessary lifetimesfn unused_lifetime<'a>(x: u8) {    // ..}

Use instead:

fn no_lifetime(x: u8) {    // ...}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

extra_unused_type_parameters📋
complexitywarn

What it does

Checks for type parameters in generics that are never used anywhere else.

Why is this bad?

Functions cannot infer the value of unused type parameters; therefore, calling themrequires using a turbofish, which serves no purpose but to satisfy the compiler.

Example

fn unused_ty<T>(x: u8) {    // ..}

Use instead:

fn no_unused_ty(x: u8) {    // ..}
Applicability:MachineApplicable(?)
Added in:1.69.0
Related Issues
View Source

fallible_impl_from📋
nurseryallow

What it does

Checks for impls ofFrom<..> that containpanic!() orunwrap()

Why is this bad?

TryFrom should be used if there’s a possibility of failure.

Example

struct Foo(i32);impl From<String> for Foo {    fn from(s: String) -> Self {        Foo(s.parse().unwrap())    }}

Use instead:

struct Foo(i32);impl TryFrom<String> for Foo {    type Error = ();    fn try_from(s: String) -> Result<Self, Self::Error> {        if let Ok(parsed) = s.parse() {            Ok(Foo(parsed))        } else {            Err(())        }    }}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

field_reassign_with_default📋
stylewarn

What it does

Checks for immediate reassignment of fields initializedwith Default::default().

Why is this bad?

It’s more idiomatic to use thefunctional update syntax.

Known problems

Assignments to patterns that are of tuple type are not linted.

Example

let mut a: A = Default::default();a.i = 42;

Use instead:

let a = A {    i: 42,    .. Default::default()};
Applicability:Unspecified(?)
Added in:1.49.0
Related Issues
View Source

field_scoped_visibility_modifiers📋
restrictionallow

What it does

Checks for usage of scoped visibility modifiers, likepub(crate), on fields. Thesemake a field visible within a scope between public and private.

Why restrict this?

Scoped visibility modifiers cause a field to be accessible within some scope betweenpublic and private, potentially within an entire crate. This allows for fields to benon-private while upholding internal invariants, but can be a code smell. Scoped visibilityrequires checking a greater area, potentially an entire crate, to verify that an invariantis upheld, and global analysis requires a lot of effort.

Example

pub mod public_module {    struct MyStruct {        pub(crate) first_field: bool,        pub(super) second_field: bool    }}

Use instead:

pub mod public_module {    struct MyStruct {        first_field: bool,        second_field: bool    }    impl MyStruct {        pub(crate) fn get_first_field(&self) -> bool {            self.first_field        }        pub(super) fn get_second_field(&self) -> bool {            self.second_field        }    }}
Applicability:Unspecified(?)
Added in:1.81.0
Related Issues
View Source

filetype_is_file📋
restrictionallow

What it does

Checks forFileType::is_file().

Why restrict this?

When people testing a file type withFileType::is_filethey are testing whether a path is something they can get bytes from. Butis_file doesn’t cover special file types in unix-like systems, and doesn’t coversymlink in windows. Using!FileType::is_dir() is a better way to that intention.

Example

let metadata = std::fs::metadata("foo.txt")?;let filetype = metadata.file_type();if filetype.is_file() {    // read file}

should be written as:

let metadata = std::fs::metadata("foo.txt")?;let filetype = metadata.file_type();if !filetype.is_dir() {    // read file}
Applicability:Unspecified(?)
Added in:1.42.0
Related Issues
View Source

filter_map_bool_then📋
stylewarn

What it does

Checks for usage ofbool::then inIterator::filter_map.

Why is this bad?

This can be written withfilter thenmap instead, which would reduce nesting andseparates the filtering from the transformation phase. This comes with no cost toperformance and is just cleaner.

Limitations

Does not lintbool::then_some, as it eagerly evaluates its arguments rather than lazily.This can create differing behavior, so better safe than sorry.

Example

_ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i)));

Use instead:

_ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
Applicability:MachineApplicable(?)
Added in:1.73.0
Related Issues
View Source

filter_map_identity📋
complexitywarn

What it does

Checks for usage offilter_map(|x| x).

Why is this bad?

Readability, this can be written more concisely by usingflatten.

Example

iter.filter_map(|x| x);

Use instead:

iter.flatten();
Applicability:MachineApplicable(?)
Added in:1.52.0
Related Issues
View Source

filter_map_next📋
pedanticallow

What it does

Checks for usage of_.filter_map(_).next().

Why is this bad?

Readability, this can be written more concisely as_.find_map(_).

Example

 (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();

Can be written as

 (0..3).find_map(|x| if x == 2 { Some(x) } else { None });

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.36.0
Related Issues
View Source

filter_next📋
complexitywarn

What it does

Checks for usage of_.filter(_).next().

Why is this bad?

Readability, this can be written more concisely as_.find(_).

Example

vec.iter().filter(|x| **x == 0).next();

Use instead:

vec.iter().find(|x| **x == 0);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

flat_map_identity📋
complexitywarn

What it does

Checks for usage offlat_map(|x| x).

Why is this bad?

Readability, this can be written more concisely by usingflatten.

Example

iter.flat_map(|x| x);

Can be written as

iter.flatten();
Applicability:MachineApplicable(?)
Added in:1.39.0
Related Issues
View Source

flat_map_option📋
pedanticallow

What it does

Checks for usage ofIterator::flat_map() wherefilter_map() could beused instead.

Why is this bad?

filter_map() is known to always produce 0 or 1 output items per input item,rather than however many the inner iterator type produces.Therefore, it maintains the upper bound inIterator::size_hint(),and communicates to the reader that the input items are not being expanded intomultiple output items without their having to notice that the mapping functionreturns anOption.

Example

let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();

Use instead:

let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
Applicability:MachineApplicable(?)
Added in:1.53.0
Related Issues
View Source

float_arithmetic📋
restrictionallow

What it does

Checks for float arithmetic.

Why restrict this?

For some embedded systems or kernel development, itcan be useful to rule out floating-point numbers.

Example

a + 1.0;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

float_cmp📋
pedanticallow

What it does

Checks for (in-)equality comparisons on floating-pointvalues (apart from zero), except in functions called*eq* (which probablyimplement equality for a type involving floats).

Why is this bad?

Floating point calculations are usually imprecise, so asking if two values areexactlyequal is asking for trouble because arriving at the same logical result via differentroutes (e.g. calculation versus constant) may yield different values.

Example

let a: f64 = 1000.1;let b: f64 = 0.2;let x = a + b;let y = 1000.3; // Expected value.// Actual value: 1000.3000000000001println!("{x}");let are_equal = x == y;println!("{are_equal}"); // false

The correct way to compare floating point numbers is to define an allowed error margin. Thismay be challenging if there is no “natural” error margin to permit. Broadly speaking, thereare two cases:

  1. If your values are in a known range and you can define a threshold for “close enough tobe equal”, it may be appropriate to define an absolute error margin. For example, if yourdata is “length of vehicle in centimeters”, you may consider 0.1 cm to be “close enough”.
  2. If your code is more general and you do not know the range of values, you should use arelative error margin, accepting e.g. 0.1% of error regardless of specific values.

For the scenario where you can define a meaningful absolute error margin, consider using:

let a: f64 = 1000.1;let b: f64 = 0.2;let x = a + b;let y = 1000.3; // Expected value.const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1;let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM;println!("{within_tolerance}"); // true

NOTE: Do not usef64::EPSILON - while the error margin is often called “epsilon”, this isa different use of the term that is not suitable for floating point equality comparison.Indeed, for the example above usingf64::EPSILON as the allowed error would returnfalse.

For the scenario where no meaningful absolute error can be defined, refer tothe floating point guidefor a reference implementation of relative error based comparison of floating point values.MIN_NORMAL in the reference implementation is equivalent toMIN_POSITIVE in Rust.

Applicability:HasPlaceholders(?)
Added in:pre 1.29.0
Related Issues
View Source

float_cmp_const📋
restrictionallow

What it does

Checks for (in-)equality comparisons on constant floating-pointvalues (apart from zero), except in functions called*eq* (which probablyimplement equality for a type involving floats).

Why restrict this?

Floating point calculations are usually imprecise, so asking if two values areexactlyequal is asking for trouble because arriving at the same logical result via differentroutes (e.g. calculation versus constant) may yield different values.

Example

let a: f64 = 1000.1;let b: f64 = 0.2;let x = a + b;const Y: f64 = 1000.3; // Expected value.// Actual value: 1000.3000000000001println!("{x}");let are_equal = x == Y;println!("{are_equal}"); // false

The correct way to compare floating point numbers is to define an allowed error margin. Thismay be challenging if there is no “natural” error margin to permit. Broadly speaking, thereare two cases:

  1. If your values are in a known range and you can define a threshold for “close enough tobe equal”, it may be appropriate to define an absolute error margin. For example, if yourdata is “length of vehicle in centimeters”, you may consider 0.1 cm to be “close enough”.
  2. If your code is more general and you do not know the range of values, you should use arelative error margin, accepting e.g. 0.1% of error regardless of specific values.

For the scenario where you can define a meaningful absolute error margin, consider using:

let a: f64 = 1000.1;let b: f64 = 0.2;let x = a + b;const Y: f64 = 1000.3; // Expected value.const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1;let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM;println!("{within_tolerance}"); // true

NOTE: Do not usef64::EPSILON - while the error margin is often called “epsilon”, this isa different use of the term that is not suitable for floating point equality comparison.Indeed, for the example above usingf64::EPSILON as the allowed error would returnfalse.

For the scenario where no meaningful absolute error can be defined, refer tothe floating point guidefor a reference implementation of relative error based comparison of floating point values.MIN_NORMAL in the reference implementation is equivalent toMIN_POSITIVE in Rust.

Applicability:HasPlaceholders(?)
Added in:pre 1.29.0
Related Issues
View Source

float_equality_without_abs📋
suspiciouswarn

What it does

Checks for statements of the form(a - b) < f32::EPSILON or(a - b) < f64::EPSILON. Note the missing.abs().

Why is this bad?

The code without.abs() is more likely to have a bug.

Known problems

If the user can ensure that b is larger than a, the.abs() istechnically unnecessary. However, it will make the code more robust and doesn’t have anylarge performance implications. If the abs call was deliberately left out for performancereasons, it is probably better to state this explicitly in the code, which then can be donewith an allow.

Example

pub fn is_roughly_equal(a: f32, b: f32) -> bool {    (a - b) < f32::EPSILON}

Use instead:

pub fn is_roughly_equal(a: f32, b: f32) -> bool {    (a - b).abs() < f32::EPSILON}
Applicability:MaybeIncorrect(?)
Added in:1.48.0
Related Issues
View Source

fn_params_excessive_bools📋
pedanticallow

What it does

Checks for excessive use ofbools in function definitions.

Why is this bad?

Calls to such functionsare confusing and error prone, because it’shard to remember argument order and you haveno type system support to back you up. Usingtwo-variant enums instead of bools often makesAPI easier to use.

Example

fn f(is_round: bool, is_hot: bool) { ... }

Use instead:

enum Shape {    Round,    Spiky,}enum Temperature {    Hot,    IceCold,}fn f(shape: Shape, temperature: Temperature) { ... }

Configuration

  • max-fn-params-bools: The maximum number of bool parameters a function can have

    (default:3)

Applicability:Unspecified(?)
Added in:1.43.0
Related Issues
View Source

fn_to_numeric_cast📋
stylewarn

What it does

Checks for casts of function pointers to something other thanusize.

Why is this bad?

Casting a function pointer to anything other thanusize/isize isnot portable across architectures. If the target type is too small theaddress would be truncated, and target types larger thanusize areunnecessary.

Casting toisize also doesn’t make sense, since addresses are neversigned.

Example

fn fun() -> i32 { 1 }let _ = fun as i64;

Use instead:

let _ = fun as usize;
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

fn_to_numeric_cast_any📋
restrictionallow

What it does

Checks for casts of a function pointer to any integer type.

Why restrict this?

Casting a function pointer to an integer can have surprising results and can occuraccidentally if parentheses are omitted from a function call. If you aren’t doing anythinglow-level with function pointers then you can opt out of casting functions to integers inorder to avoid mistakes. Alternatively, you can use this lint to audit all uses of functionpointer casts in your code.

Example

// fn1 is cast as `usize`fn fn1() -> u16 {    1};let _ = fn1 as usize;

Use instead:

// maybe you intended to call the function?fn fn2() -> u16 {    1};let _ = fn2() as usize;// or// maybe you intended to cast it to a function type?fn fn3() -> u16 {    1}let _ = fn3 as fn() -> u16;
Applicability:MaybeIncorrect(?)
Added in:1.58.0
Related Issues
View Source

fn_to_numeric_cast_with_truncation📋
stylewarn

What it does

Checks for casts of a function pointer to a numeric type not wide enough tostore an address.

Why is this bad?

Such a cast discards some bits of the function’s address. If this is intended, it would be moreclearly expressed by casting tousize first, then casting theusize to the intended type (witha comment) to perform the truncation.

Example

fn fn1() -> i16 {    1};let _ = fn1 as i32;

Use instead:

// Cast to usize first, then comment with the reason for the truncationfn fn1() -> i16 {    1};let fn_ptr = fn1 as usize;let fn_ptr_truncated = fn_ptr as i32;
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

for_kv_map📋
stylewarn

What it does

Checks for iterating a map (HashMap orBTreeMap) andignoring either the keys or values.

Why is this bad?

Readability. There arekeys andvalues methods thatcan be used to express that don’t need the values or keys.

Example

for (k, _) in &map {    ..}

could be replaced by

for k in map.keys() {    ..}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

forget_non_drop📋
suspiciouswarn

What it does

Checks for calls tostd::mem::forget with a value that does not implementDrop.

Why is this bad?

Callingstd::mem::forget is no different than dropping such a type. A different value mayhave been intended.

Example

struct Foo;let x = Foo;std::mem::forget(x);
Applicability:Unspecified(?)
Added in:1.62.0
Related Issues
View Source

format_collect📋
pedanticallow

What it does

Checks for usage of.map(|_| format!(..)).collect::<String>().

Why is this bad?

This allocates a new string for every element in the iterator.This can be done more efficiently by creating theString once and appending to it inIterator::fold,using either thewrite! macro which supports exactly the same syntax as theformat! macro,or concatenating with+ in case the iterator yields&str/String.

Note also thatwrite!-ing into aString can never fail, despite the return type ofwrite! beingstd::fmt::Result,so it can be safely ignored or unwrapped.

Example

fn hex_encode(bytes: &[u8]) -> String {    bytes.iter().map(|b| format!("{b:02X}")).collect()}

Use instead:

use std::fmt::Write;fn hex_encode(bytes: &[u8]) -> String {    bytes.iter().fold(String::new(), |mut output, b| {        let _ = write!(output, "{b:02X}");        output    })}
Applicability:Unspecified(?)
Added in:1.73.0
Related Issues
View Source

format_in_format_args📋
perfwarn

What it does

Detectsformat! within the arguments of another macro that doesformatting such asformat! itself,write! orprintln!. Suggestsinlining theformat! call.

Why is this bad?

The recommended code is both shorter and avoids a temporary allocation.

Example

println!("error: {}", format!("something failed at {}", Location::caller()));

Use instead:

println!("error: something failed at {}", Location::caller());
Applicability:Unspecified(?)
Added in:1.58.0
Related Issues
View Source

format_push_string📋
pedanticallow

What it does

Detects cases where the result of aformat! call isappended to an existingString.

Why is this bad?

Introduces an extra, avoidable heap allocation.

Known problems

format! returns aString butwrite! returns aResult.Thus you are forced to ignore theErr variant to achieve the same API.

While usingwrite! in the suggested way should never fail, this isn’t necessarily clear to the programmer.

Example

let mut s = String::new();s += &format!("0x{:X}", 1024);s.push_str(&format!("0x{:X}", 1024));

Use instead:

use std::fmt::Write as _; // import without risk of name clashinglet mut s = String::new();let _ = write!(s, "0x{:X}", 1024);
Applicability:Unspecified(?)
Added in:1.62.0
Related Issues
View Source

four_forward_slashes📋
suspiciouswarn

What it does

Checks for outer doc comments written with 4 forward slashes (////).

Why is this bad?

This is (probably) a typo, and results in it not being a doc comment; just a regularcomment.

Example

//// My amazing data structurepub struct Foo {    // ...}

Use instead:

/// My amazing data structurepub struct Foo {    // ...}
Applicability:MachineApplicable(?)
Added in:1.73.0
Related Issues
View Source

from_iter_instead_of_collect📋
pedanticallow

What it does

Checks forfrom_iter() function calls on types that implement theFromIteratortrait.

Why is this bad?

If it’s needed to create a collection from the contents of an iterator, theIterator::collect(_)method is preferred. However, when it’s needed to specify the container type,Vec::from_iter(_) can be more readable than using a turbofish (e.g._.collect::<Vec<_>>()). SeeFromIterator documentation

Example

let five_fives = std::iter::repeat(5).take(5);let v = Vec::from_iter(five_fives);assert_eq!(v, vec![5, 5, 5, 5, 5]);

Use instead:

let five_fives = std::iter::repeat(5).take(5);let v: Vec<i32> = five_fives.collect();assert_eq!(v, vec![5, 5, 5, 5, 5]);

but prefer to use

let numbers: Vec<i32> = FromIterator::from_iter(1..=5);

instead of

let numbers = (1..=5).collect::<Vec<_>>();
Applicability:MaybeIncorrect(?)
Added in:1.49.0
Related Issues
View Source

from_over_into📋
stylewarn

What it does

Searches for implementations of theInto<..> trait and suggests to implementFrom<..> instead.

Why is this bad?

According the std docs implementingFrom<..> is preferred since it gives youInto<..> for free where the reverse isn’t true.

Example

struct StringWrapper(String);impl Into<StringWrapper> for String {    fn into(self) -> StringWrapper {        StringWrapper(self)    }}

Use instead:

struct StringWrapper(String);impl From<String> for StringWrapper {    fn from(s: String) -> StringWrapper {        StringWrapper(s)    }}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.51.0
Related Issues
View Source

from_raw_with_void_ptr📋
suspiciouswarn

What it does

Checks if we’re passing ac_void raw pointer to{Box,Rc,Arc,Weak}::from_raw(_)

Why is this bad?

When dealing withc_void raw pointers in FFI, it is easy to run into the pitfall of callingfrom_raw with thec_void pointer.The type signature ofBox::from_raw isfn from_raw(raw: *mut T) -> Box<T>, so if you pass a*mut c_void you will get aBox<c_void> (and similarly forRc,Arc andWeak).For this to be safe,c_void would need to have the same memory layout as the original type, which is often not the case.

Example

let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;let _ = unsafe { Box::from_raw(ptr) };

Use instead:

let _ = unsafe { Box::from_raw(ptr as *mut usize) };
Applicability:Unspecified(?)
Added in:1.67.0
Related Issues
View Source

from_str_radix_10📋
stylewarn

What it does

Checks for function invocations of the formprimitive::from_str_radix(s, 10)

Why is this bad?

This specific common use case can be rewritten ass.parse::<primitive>()(and in most cases, the turbofish can be removed), which reduces code lengthand complexity.

Known problems

This lint may suggest using(&<expression>).parse() instead of<expression>.parse()directly in some cases, which is correct but adds unnecessary complexity to the code.

Example

let input: &str = get_input();let num = u16::from_str_radix(input, 10)?;

Use instead:

let input: &str = get_input();let num: u16 = input.parse()?;
Applicability:MaybeIncorrect(?)
Added in:1.52.0
Related Issues
View Source

future_not_send📋
nurseryallow

What it does

This lint requires Future implementations returned fromfunctions and methods to implement theSend marker trait,ignoring type parameters.

If a function is generic and its Future conditionally implementsSendbased on a generic parameter then it is consideredSend and no warning is emitted.

This can be used by library authors (public and internal) to ensuretheir functions are compatible with both multi-threaded runtimes that requireSend futures,as well as single-threaded runtimes where callers may choose!Send typesfor generic parameters.

Why is this bad?

A Future implementation captures some state that itneeds to eventually produce its final value. When targeting a multithreadedexecutor (which is the norm on non-embedded devices) this means that thisstate may need to be transported to other threads, in other words thewhole Future needs to implement theSend marker trait. If it does not,then the resulting Future cannot be submitted to a thread pool in theend user’s code.

Especially for generic functions it can be confusing to leave thediscovery of this problem to the end user: the reported error locationwill be far from its cause and can in many cases not even be fixed withoutmodifying the library where the offending Future implementation isproduced.

Example

async fn not_send(bytes: std::rc::Rc<[u8]>) {}

Use instead:

async fn is_send(bytes: std::sync::Arc<[u8]>) {}
Applicability:Unspecified(?)
Added in:1.44.0
Related Issues
View Source

get_first📋
stylewarn

What it does

Checks for usage ofx.get(0) instead ofx.first() orx.front().

Why is this bad?

Usingx.first() forVecs and slices orx.front()forVecDeques is easier to read and has the same result.

Example

let x = vec![2, 3, 5];let first_element = x.get(0);

Use instead:

let x = vec![2, 3, 5];let first_element = x.first();
Applicability:MachineApplicable(?)
Added in:1.63.0
Related Issues
View Source

get_last_with_len📋
complexitywarn

What it does

Checks for usage ofx.get(x.len() - 1) instead ofx.last().

Why is this bad?

Usingx.last() is easier to read and has the sameresult.

Note that usingx[x.len() - 1] is semantically different fromx.last(). Indexing into the array will panic on out-of-boundsaccesses, whilex.get() andx.last() will returnNone.

There is another lint (get_unwrap) that covers the case of usingx.get(index).unwrap() instead ofx[index].

Example

let x = vec![2, 3, 5];let last_element = x.get(x.len() - 1);

Use instead:

let x = vec![2, 3, 5];let last_element = x.last();
Applicability:MachineApplicable(?)
Added in:1.37.0
Related Issues
View Source

get_unwrap📋
restrictionallow

What it does

Checks for usage of.get().unwrap() (or.get_mut().unwrap) on a standard library type which implementsIndex

Why restrict this?

Using the Index trait ([]) is more clear and moreconcise.

Known problems

Not a replacement for error handling: Using either.unwrap() or the Index trait ([]) carries the risk of causing apanicif the value being accessed isNone. If the use of.get().unwrap() is atemporary placeholder for dealing with theOption type, then this doesnot mitigate the need for error handling. If there is a chance that.get()will beNone in your program, then it is advisable that theNone caseis handled in a future refactor instead of using.unwrap() or the Indextrait.

Example

let mut some_vec = vec![0, 1, 2, 3];let last = some_vec.get(3).unwrap();*some_vec.get_mut(0).unwrap() = 1;

The correct use would be:

let mut some_vec = vec![0, 1, 2, 3];let last = some_vec[3];some_vec[0] = 1;
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

host_endian_bytes📋
restrictionallow

What it does

Checks for the usage of theto_ne_bytes method and/or the functionfrom_ne_bytes.

Why restrict this?

To ensure use of explicitly chosen endianness rather than the target’s endianness,such as when implementing network protocols or file formats rather than FFI.

Example

let _x = 2i32.to_ne_bytes();let _y = 2i64.to_ne_bytes();
Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

identity_op📋
complexitywarn

What it does

Checks for identity operations, e.g.,x + 0.

Why is this bad?

This code can be removed without changing themeaning. So it just obscures what’s going on. Delete it mercilessly.

Example

x / 1 + 0 * 1 - 0 | 0;
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

if_let_mutex📋
correctnessdeny

What it does

Checks forMutex::lock calls inif let expressionwith lock calls in any of the else blocks.

Disabled starting in Edition 2024

This lint is effectively disabled starting inEdition 2024 asif let ... else scoping was reworkedsuch that this is no longer an issue. SeeProposal: stabilize if_let_rescope for Edition 2024

Why is this bad?

The Mutex lock remains held for the wholeif let ... else block and deadlocks.

Example

if let Ok(thing) = mutex.lock() {    do_thing();} else {    mutex.lock();}

Should be written

let locked = mutex.lock();if let Ok(thing) = locked {    do_thing(thing);} else {    use_locked(locked);}
Applicability:Unspecified(?)
Added in:1.45.0
Related Issues
View Source

if_not_else📋
pedanticallow

What it does

Checks for usage of! or!= in an if condition with anelse branch.

Why is this bad?

Negations reduce the readability of statements.

Example

if !v.is_empty() {    a()} else {    b()}

Could be written:

if v.is_empty() {    b()} else {    a()}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

if_same_then_else📋
stylewarn

What it does

Checks forif/else with the same body as thethen partand theelse part.

Why is this bad?

This is probably a copy & paste error.

Example

let foo = if … {    42} else {    42};
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

if_then_some_else_none📋
restrictionallow

What it does

Checks for if-else that could be written using eitherbool::then orbool::then_some.

Why restrict this?

Looks a little redundant. Usingbool::then is more concise and incurs no loss of clarity.For simple calculations and known values, usebool::then_some, which is eagerly evaluatedin comparison tobool::then.

Example

let a = if v.is_empty() {    println!("true!");    Some(42)} else {    None};

Could be written:

let a = v.is_empty().then(|| {    println!("true!");    42});

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.53.0
Related Issues
View Source

ifs_same_cond📋
correctnessdeny

What it does

Checks for consecutiveifs with the same condition.

Why is this bad?

This is probably a copy & paste error.

Example

if a == b {    …} else if a == b {    …}

Note that this lint ignores all conditions with a function call as it couldhave side effects:

if foo() {    …} else if foo() { // not linted    …}

Configuration

  • ignore-interior-mutability: A list of paths to types that should be treated as if they do not contain interior mutability

    (default:["bytes::Bytes"])

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

ignore_without_reason📋
pedanticallow

What it does

Checks for ignored tests without messages.

Why is this bad?

The reason for ignoring the test may not be obvious.

Example

#[test]#[ignore]fn test() {}

Use instead:

#[test]#[ignore = "Some good reason"]fn test() {}
Applicability:Unspecified(?)
Added in:1.88.0
Related Issues
View Source

ignored_unit_patterns📋
pedanticallow

What it does

Checks for usage of_ in patterns of type().

Why is this bad?

Matching with() explicitly instead of_ outlinesthe fact that the pattern contains no data. Also itwould detect a type change that_ would ignore.

Example

match std::fs::create_dir("tmp-work-dir") {    Ok(_) => println!("Working directory created"),    Err(s) => eprintln!("Could not create directory: {s}"),}

Use instead:

match std::fs::create_dir("tmp-work-dir") {    Ok(()) => println!("Working directory created"),    Err(s) => eprintln!("Could not create directory: {s}"),}
Applicability:MachineApplicable(?)
Added in:1.73.0
Related Issues
View Source

impl_hash_borrow_with_str_and_bytes📋
correctnessdeny

What it does

This lint is concerned with the semantics ofBorrow andHash for atype that implements all three ofHash,Borrow<str> andBorrow<[u8]>as it is impossible to satisfy the semantics of Borrow andHash forbothBorrow<str> andBorrow<[u8]>.

Why is this bad?

When providing implementations forBorrow<T>, one should consider whether the differentimplementations should act as facets or representations of the underlying type. Generic codetypically usesBorrow<T> when it relies on the identical behavior of these additional traitimplementations. These traits will likely appear as additional trait bounds.

In particularEq,Ord andHash must be equivalent for borrowed and owned values:x.borrow() == y.borrow() should give the same result asx == y.It follows then that the following equivalence must hold:hash(x) == hash((x as Borrow<[u8]>).borrow()) == hash((x as Borrow<str>).borrow())

Unfortunately it doesn’t hold ashash("abc") != hash("abc".as_bytes()).This happens because theHash impl for str passes an additional0xFF byte tothe hasher to avoid collisions. For example, given the tuples("a", "bc"), and("ab", "c"),the two tuples would have the same hash value if the0xFF byte was not added.

Example

use std::borrow::Borrow;use std::hash::{Hash, Hasher};struct ExampleType {    data: String}impl Hash for ExampleType {    fn hash<H: Hasher>(&self, state: &mut H) {        self.data.hash(state);    }}impl Borrow<str> for ExampleType {    fn borrow(&self) -> &str {        &self.data    }}impl Borrow<[u8]> for ExampleType {    fn borrow(&self) -> &[u8] {        self.data.as_bytes()    }}

As a consequence, hashing a&ExampleType and hashing the result of the twoborrows will result in different values.

Applicability:Unspecified(?)
Added in:1.76.0
Related Issues
View Source

impl_trait_in_params📋
restrictionallow

What it does

Lints whenimpl Trait is being used in a function’s parameters.

Why restrict this?

Turbofish syntax (::<>) cannot be used to specify the type of animpl Trait parameter,makingimpl Trait less powerful. Readability may also be a factor.

Example

trait MyTrait {}fn foo(a: impl MyTrait) {// [...]}

Use instead:

trait MyTrait {}fn foo<T: MyTrait>(a: T) {// [...]}
Applicability:HasPlaceholders(?)
Added in:1.69.0
Related Issues
View Source

implicit_clone📋
pedanticallow

What it does

Checks for the usage of_.to_owned(),vec.to_vec(), or similar when calling_.clone() would be clearer.

Why is this bad?

These methods do the same thing as_.clone() but may be confusing asto why we are callingto_vec on something that is already aVec or callingto_owned on something that is already owned.

Example

let a = vec![1, 2, 3];let b = a.to_vec();let c = a.to_owned();

Use instead:

let a = vec![1, 2, 3];let b = a.clone();let c = a.clone();
Applicability:MachineApplicable(?)
Added in:1.52.0
Related Issues
View Source

implicit_hasher📋
pedanticallow

What it does

Checks for publicimpl orfn missing generalizationover different hashers and implicitly defaulting to the default hashingalgorithm (SipHash).

Why is this bad?

HashMap orHashSet with custom hashers cannot beused with them.

Known problems

Suggestions for replacing constructors can containfalse-positives. Also applying suggestions can require modification of otherpieces of code, possibly including external crates.

Example

impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }pub fn foo(map: &mut HashMap<i32, i32>) { }

could be rewritten as

impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

implicit_return📋
restrictionallow

What it does

Checks for missing return statements at the end of a block.

Why restrict this?

Omitting the return keyword whenever possible is idiomatic Rust code, but:

  • Programmers coming from other languages might prefer the expressiveness ofreturn.
  • 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 areturn keyword makes it easier to find thecorresponding statements.

Example

fn foo(x: usize) -> usize {    x}

add return

fn foo(x: usize) -> usize {    return x;}
Applicability:MachineApplicable(?)
Added in:1.33.0
Related Issues
View Source

implicit_saturating_add📋
stylewarn

What it does

Checks for implicit saturating addition.

Why is this bad?

The built-in function is more readable and may be faster.

Example

let mut u:u32 = 7000;if u != u32::MAX {    u += 1;}

Use instead:

let mut u:u32 = 7000;u = u.saturating_add(1);
Applicability:MachineApplicable(?)
Added in:1.66.0
Related Issues
View Source

implicit_saturating_sub📋
stylewarn

What it does

Checks for implicit saturating subtraction.

Why is this bad?

Simplicity and readability. Instead we can easily use an builtin function.

Example

let mut i: u32 = end - start;if i != 0 {    i -= 1;}

Use instead:

let mut i: u32 = end - start;i = i.saturating_sub(1);
Applicability:MachineApplicable(?)
Added in:1.44.0
Related Issues
View Source

implied_bounds_in_impls📋
complexitywarn

What it does

Looks for bounds inimpl Trait in return position that are implied by other bounds.This can happen when a trait is specified that another trait already has as a supertrait(e.g.fn() -> impl Deref + DerefMut<Target = i32> has an unnecessaryDeref bound,becauseDeref is a supertrait ofDerefMut)

Why is this bad?

Specifying more bounds than necessary adds needless complexity for the reader.

Limitations

This lint does not check for implied bounds transitively. Meaning thatit doesn’t check for implied bounds from supertraits of supertraits(e.g.trait A {} trait B: A {} trait C: B {}, then having anfn() -> impl A + C)

Example

fn f() -> impl Deref<Target = i32> + DerefMut<Target = i32> {//             ^^^^^^^^^^^^^^^^^^^ unnecessary bound, already implied by the `DerefMut` trait bound    Box::new(123)}

Use instead:

fn f() -> impl DerefMut<Target = i32> {    Box::new(123)}
Applicability:MachineApplicable(?)
Added in:1.74.0
Related Issues
View Source

impossible_comparisons📋
correctnessdeny

What it does

Checks for double comparisons that can never succeed

Why is this bad?

The whole expression can be replaced byfalse,which is probably not the programmer’s intention

Example

if status_code <= 400 && status_code > 500 {}
Applicability:Unspecified(?)
Added in:1.73.0
Related Issues
View Source

imprecise_flops📋
nurseryallow

What it does

Looks for floating-point expressions thatcan be expressed using built-in methods to improve accuracyat the cost of performance.

Why is this bad?

Negatively impacts accuracy.

Example

let a = 3f32;let _ = a.powf(1.0 / 3.0);let _ = (1.0 + a).ln();let _ = a.exp() - 1.0;

Use instead:

let a = 3f32;let _ = a.cbrt();let _ = a.ln_1p();let _ = a.exp_m1();
Applicability:MachineApplicable(?)
Added in:1.43.0
Related Issues
View Source

incompatible_msrv📋
suspiciouswarn

What it does

This lint checks that no function newer than the defined MSRV (minimumsupported rust version) is used in the crate.

Why is this bad?

It would prevent the crate to be actually used with the specified MSRV.

Example

// MSRV of 1.3.0use std::thread::sleep;use std::time::Duration;// Sleep was defined in `1.4.0`.sleep(Duration::new(1, 0));

To fix this problem, either increase your MSRV or use another itemavailable in your current MSRV.

You can also locally change the MSRV that should be checked by Clippy,for example if a feature in your crate (e.g.,modern_compiler) shouldallow you to use an item:

//! This crate has a MSRV of 1.3.0, but we also have an optional feature//! `sleep_well` which requires at least Rust 1.4.0.// When the `sleep_well` feature is set, do not warn for functions available// in Rust 1.4.0 and below.#![cfg_attr(feature = "sleep_well", clippy::msrv = "1.4.0")]use std::time::Duration;#[cfg(feature = "sleep_well")]fn sleep_for_some_time() {    std::thread::sleep(Duration::new(1, 0)); // Will not trigger the lint}

You can also increase the MSRV in tests, by using:

// Use a much higher MSRV for tests while keeping the main one low#![cfg_attr(test, clippy::msrv = "1.85.0")]#[test]fn my_test() {    // The tests can use items introduced in Rust 1.85.0 and lower    // without triggering the `incompatible_msrv` lint.}

Configuration

  • check-incompatible-msrv-in-tests: Whether to check MSRV compatibility in#[test] and#[cfg(test)] code.

    (default:false)

Applicability:Unspecified(?)
Added in:1.78.0
Related Issues
View Source

inconsistent_digit_grouping📋
stylewarn

What it does

Warns if an integral or floating-point constant isgrouped inconsistently with underscores.

Why is this bad?

Readers may incorrectly interpret inconsistentlygrouped digits.

Example

618_64_9189_73_511

Use instead:

61_864_918_973_511
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

inconsistent_struct_constructor📋
pedanticallow

What it does

Checks for struct constructors where the order of the fieldinit in the constructor is inconsistent with the order in thestruct definition.

Why is this bad?

Since the order of fields in a constructor doesn’t affect theresulted instance as the below example indicates,

#[derive(Debug, PartialEq, Eq)]struct Foo {    x: i32,    y: i32,}let x = 1;let y = 2;// This assertion never fails:assert_eq!(Foo { x, y }, Foo { y, x });

inconsistent order can be confusing and decreases readability and consistency.

Example

struct Foo {    x: i32,    y: i32,}let x = 1;let y = 2;Foo { y, x };

Use instead:

Foo { x, y };

Configuration

  • check-inconsistent-struct-field-initializers: Whether to suggest reordering constructor fields when initializers are present.

Warnings produced by this configuration aren’t necessarily fixed by just reordering the fields. Even if thesuggested code would compile, it can change semantics if the initializer expressions have side effects. Thefollowing examplefrom rust-clippy#11846 shows how the suggestion can run into borrow check errors:

struct MyStruct {    vector: Vec<u32>,    length: usize}fn main() {    let vector = vec![1,2,3];    MyStruct { length: vector.len(), vector};}

(default:false)

Applicability:MachineApplicable(?)
Added in:1.52.0
Related Issues
View Source

index_refutable_slice📋
pedanticallow

What it does

The lint checks for slice bindings in patterns that are only used toaccess individual slice values.

Why is this bad?

Accessing slice values using indices can lead to panics. Using refutablepatterns can avoid these. Binding to individual values also improves thereadability as they can be named.

Limitations

This lint currently only checks for immutable access insideif letpatterns.

Example

let slice: Option<&[u32]> = Some(&[1, 2, 3]);if let Some(slice) = slice {    println!("{}", slice[0]);}

Use instead:

let slice: Option<&[u32]> = Some(&[1, 2, 3]);if let Some(&[first, ..]) = slice {    println!("{}", first);}

Configuration

  • max-suggested-slice-pattern-length: When Clippy suggests using a slice pattern, this is the maximum number of elements allowed inthe slice pattern that is suggested. If more elements are necessary, the lint is suppressed.For example,[_, _, _, e, ..] is a slice pattern with 4 elements.

    (default:3)

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.59.0
Related Issues
View Source

indexing_slicing📋
restrictionallow

What it does

Checks for usage of indexing or slicing that may panic at runtime.

This lint does not report on indexing or slicing operationsthat always panic, clippy’sout_of_bound_indexing alreadyhandles those cases.

Why restrict this?

To avoid implicit panics from indexing and slicing.

There are “checked” alternatives which do not panic, and can be used withunwrap() to makean explicit panic when it is desired.

Limitations

This lint does not check for the usage of indexing or slicing on strings. These are coveredby the more specificstring_slice lint.

Example

// Vectorlet x = vec![0, 1, 2, 3];x[2];x[100];&x[2..100];// Arraylet y = [0, 1, 2, 3];let i = 10; // Could be a runtime valuelet j = 20;&y[i..j];

Use instead:

x.get(2);x.get(100);x.get(2..100);let i = 10;let j = 20;y.get(i..j);

Configuration

  • allow-indexing-slicing-in-tests: Whetherindexing_slicing should be allowed in test functions or#[cfg(test)]

    (default:false)

  • suppress-restriction-lint-in-const: Whether to suppress a restriction lint in constant code. In samecases the restructured operation might not be unavoidable, as thesuggested counterparts are unavailable in constant code. Thisconfiguration will cause restriction lints to trigger evenif no suggestion can be made.

    (default:false)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

ineffective_bit_mask📋
correctnessdeny

What it does

Checks for bit masks in comparisons which can be removedwithout changing the outcome. The basic structure can be seen in thefollowing table:

ComparisonBit OpExampleequals
> /<=| /^x | 2 > 3x > 3
< />=| /^x ^ 1 < 4x < 4

Why is this bad?

Not equally evil asbad_bit_mask,but still a bit misleading, because the bit mask is ineffective.

Known problems

False negatives: This lint will only match instanceswhere we have figured out the math (which is for a power-of-two comparedvalue). This means things likex | 1 >= 7 (which would be better writtenasx >= 6) will not be reported (but bit masks like this are fairlyuncommon).

Example

if (x | 1 > 3) {  }

Use instead:

if (x >= 2) {  }
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

ineffective_open_options📋
suspiciouswarn

What it does

Checks if both.write(true) and.append(true) methods are calledon a sameOpenOptions.

Why is this bad?

.append(true) already enableswrite(true), making this onesuperfluous.

Example

let _ = OpenOptions::new()           .write(true)           .append(true)           .create(true)           .open("file.json");

Use instead:

let _ = OpenOptions::new()           .append(true)           .create(true)           .open("file.json");
Applicability:MachineApplicable(?)
Added in:1.76.0
Related Issues
View Source

inefficient_to_string📋
pedanticallow

What it does

Checks for usage of.to_string() on an&&T whereT implementsToString directly (like&&str or&&String).

Why is this bad?

In versions of the compiler before Rust 1.82.0, this bypasses the specializedimplementation ofToString and instead goes through the more expensive stringformatting facilities.

Example

// Generic implementation for `T: Display` is used (slow)["foo", "bar"].iter().map(|s| s.to_string());// OK, the specialized impl is used["foo", "bar"].iter().map(|&s| s.to_string());

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.40.0
Related Issues
View Source

infallible_destructuring_match📋
stylewarn

What it does

Checks for matches being used to destructure a single-variant enumor tuple struct where alet will suffice.

Why is this bad?

Just readability –let doesn’t nest, whereas amatch does.

Example

enum Wrapper {    Data(i32),}let wrapper = Wrapper::Data(42);let data = match wrapper {    Wrapper::Data(i) => i,};

The correct use would be:

enum Wrapper {    Data(i32),}let wrapper = Wrapper::Data(42);let Wrapper::Data(data) = wrapper;
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

infallible_try_from📋
suspiciouswarn

What it does

Finds manual impls ofTryFrom with infallible error types.

Why is this bad?

Infallible conversions should be implemented viaFrom with the blanket conversion.

Example

use std::convert::Infallible;struct MyStruct(i16);impl TryFrom<i16> for MyStruct {    type Error = Infallible;    fn try_from(other: i16) -> Result<Self, Infallible> {        Ok(Self(other.into()))    }}

Use instead:

struct MyStruct(i16);impl From<i16> for MyStruct {    fn from(other: i16) -> Self {        Self(other)    }}
Applicability:Unspecified(?)
Added in:1.89.0
Related Issues
View Source

infinite_iter📋
correctnessdeny

What it does

Checks for iteration that is guaranteed to be infinite.

Why is this bad?

While there may be places where this is acceptable(e.g., in event streams), in most cases this is simply an error.

Example

use std::iter;iter::repeat(1_u8).collect::<Vec<_>>();
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

infinite_loop📋
restrictionallow

What it does

Checks for infinite loops in a function where the return type is not!and lint accordingly.

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

fn run_forever() {    loop {        // do something    }}

If infinite loops are as intended:

fn run_forever() -> ! {    loop {        // do something    }}

Otherwise add abreak orreturn condition:

fn run_forever() {    loop {        // do something        if condition {            break;        }    }}
Applicability:MaybeIncorrect(?)
Added in:1.76.0
Related Issues
View Source

inherent_to_string📋
stylewarn

What it does

Checks for the definition of inherent methods with a signature ofto_string(&self) -> String.

Why is this bad?

This method is also implicitly defined if a type implements theDisplay trait. As the functionality ofDisplay is much more versatile, it should be preferred.

Example

pub struct A;impl A {    pub fn to_string(&self) -> String {        "I am A".to_string()    }}

Use instead:

use std::fmt;pub struct A;impl fmt::Display for A {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        write!(f, "I am A")    }}
Applicability:Unspecified(?)
Added in:1.38.0
Related Issues
View Source

inherent_to_string_shadow_display📋
correctnessdeny

What it does

Checks for the definition of inherent methods with a signature ofto_string(&self) -> String and if the type implementing this method also implements theDisplay trait.

Why is this bad?

This method is also implicitly defined if a type implements theDisplay trait. The less versatile inherent method will then shadow the implementation introduced byDisplay.

Example

use std::fmt;pub struct A;impl A {    pub fn to_string(&self) -> String {        "I am A".to_string()    }}impl fmt::Display for A {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        write!(f, "I am A, too")    }}

Use instead:

use std::fmt;pub struct A;impl fmt::Display for A {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        write!(f, "I am A")    }}
Applicability:Unspecified(?)
Added in:1.38.0
Related Issues
View Source

init_numbered_fields📋
stylewarn

What it does

Checks for tuple structs initialized with field syntax.It will however not lint if a base initializer is present.The lint will also ignore code in macros.

Why is this bad?

This may be confusing to the uninitiated and adds nobenefit as opposed to tuple initializers

Example

struct TupleStruct(u8, u16);let _ = TupleStruct {    0: 1,    1: 23,};// should be written aslet base = TupleStruct(1, 23);// This is OK howeverlet _ = TupleStruct { 0: 42, ..base };
Applicability:MachineApplicable(?)
Added in:1.59.0
Related Issues
View Source

inline_always📋
pedanticallow

What it does

Checks for items annotated with#[inline(always)],unless the annotated function is empty or simply panics.

Why is this bad?

While there are valid uses of this annotation (and onceyou know when to use it, by all meansallow this lint), it’s a commonnewbie-mistake to pepper one’s code with it.

As a rule of thumb, before slapping#[inline(always)] on a function,measure if that additional function call really affects your runtime profilesufficiently to make up for the increase in compile time.

Known problems

False positives, big time. This lint is meant to bedeactivated by everyone doing serious performance work. This means havingdone the measurement.

Example

#[inline(always)]fn not_quite_hot_code(..) { ... }
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

inline_asm_x86_att_syntax📋
restrictionallow

What it does

Checks for usage of AT&T x86 assembly syntax.

Why restrict this?

To enforce consistent use of Intel x86 assembly syntax.

Example

asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));

Use instead:

asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
Applicability:Unspecified(?)
Added in:1.49.0
Related Issues
View Source

inline_asm_x86_intel_syntax📋
restrictionallow

What it does

Checks for usage of Intel x86 assembly syntax.

Why restrict this?

To enforce consistent use of AT&T x86 assembly syntax.

Example

asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);

Use instead:

asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
Applicability:Unspecified(?)
Added in:1.49.0
Related Issues
View Source

inline_fn_without_body📋
correctnessdeny

What it does

Checks for#[inline] on trait methods without bodies

Why is this bad?

Only implementations of trait methods may be inlined.The inline attribute is ignored for trait methods without bodies.

Example

trait Animal {    #[inline]    fn name(&self) -> &'static str;}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

inspect_for_each📋
complexitywarn

What it does

Checks for usage ofinspect().for_each().

Why is this bad?

It is the same as performing the computationinsideinspect at the beginning of the closure infor_each.

Example

[1,2,3,4,5].iter().inspect(|&x| println!("inspect the number: {}", x)).for_each(|&x| {    assert!(x >= 0);});

Can be written as

[1,2,3,4,5].iter().for_each(|&x| {    println!("inspect the number: {}", x);    assert!(x >= 0);});
Applicability:Unspecified(?)
Added in:1.51.0
Related Issues
View Source

int_plus_one📋
complexitywarn

What it does

Checks for usage ofx >= y + 1 orx - 1 >= y (and<=) in a block

Why is this bad?

Readability – better to use> y instead of>= y + 1.

Example

if x >= y + 1 {}

Use instead:

if x > y {}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

integer_division📋
restrictionallow

What it does

Checks for division of integers

Why restrict this?

When outside of some very specific algorithms,integer division is very often a mistake because it discards theremainder.

Example

let x = 3 / 2;println!("{}", x);

Use instead:

let x = 3f32 / 2f32;println!("{}", x);
Applicability:Unspecified(?)
Added in:1.37.0
Related Issues
View Source

integer_division_remainder_used📋
restrictionallow

What it does

Checks for the usage of division (/) and remainder (%) operationswhen performed on any integer types using the defaultDiv andRem trait implementations.

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).

Example

let my_div = 10 / 2;

Use instead:

let my_div = 10 >> 1;
Applicability:Unspecified(?)
Added in:1.79.0
Related Issues
View Source

into_iter_on_ref📋
stylewarn

What it does

Checks forinto_iter calls on references which should be replaced byiteroriter_mut.

Why is this bad?

Readability. Callinginto_iter on a reference will not move out itscontent into the resulting iterator, which is confusing. It is better just calliter oriter_mut directly.

Example

(&vec).into_iter();

Use instead:

(&vec).iter();
Applicability:MachineApplicable(?)
Added in:1.32.0
Related Issues
View Source

into_iter_without_iter📋
pedanticallow

What it does

This is the opposite of theiter_without_into_iter lint.It looks forIntoIterator for (&|&mut) Type implementations without an inherentiter oriter_mut methodon the type or on any of the types in itsDeref chain.

Why is this bad?

It’s not bad, but having them is idiomatic and allows the type to be used in iterator chainsby just calling.iter(), instead of the more awkward<&Type>::into_iter or(&val).into_iter() syntaxin case of ambiguity with anotherIntoIterator impl.

Limitations

This lint focuses on providing an idiomatic API. Therefore, it will onlylint on types which are accessible outside of the crate. For internal types,these methods can be added on demand if they are actually needed. Otherwise,it would trigger thedead_code lint for the unused method.

Example

struct MySlice<'a>(&'a [u8]);impl<'a> IntoIterator for &MySlice<'a> {    type Item = &'a u8;    type IntoIter = std::slice::Iter<'a, u8>;    fn into_iter(self) -> Self::IntoIter {        self.0.iter()    }}

Use instead:

struct MySlice<'a>(&'a [u8]);impl<'a> MySlice<'a> {    pub fn iter(&self) -> std::slice::Iter<'a, u8> {        self.into_iter()    }}impl<'a> IntoIterator for &MySlice<'a> {    type Item = &'a u8;    type IntoIter = std::slice::Iter<'a, u8>;    fn into_iter(self) -> Self::IntoIter {        self.0.iter()    }}
Applicability:Unspecified(?)
Added in:1.75.0
Related Issues
View Source

invalid_regex📋
correctnessdeny

What it does

Checksregex creation(withRegex::new,RegexBuilder::new, orRegexSet::new) for correctregex syntax.

Why is this bad?

This will lead to a runtime panic.

Example

Regex::new("(")

Use instead:

Regex::new("\(")
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

invalid_upcast_comparisons📋
pedanticallow

What it does

Checks for comparisons where the relation is always eithertrue or false, but where one side has been upcast so that the comparison isnecessary. Only integer types are checked.

Why is this bad?

An expression likelet x : u8 = ...; (x as u32) > 300will mistakenly imply that it is possible forx to be outside the range ofu8.

Example

let x: u8 = 1;(x as u32) > 300;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

inverted_saturating_sub📋
correctnessdeny

What it does

Checks for comparisons between integers, followed by subtracting the greater value from thelower one.

Why is this bad?

This could result in an underflow and is most likely not what the user wants. If this wasintended to be a saturated subtraction, consider using thesaturating_sub method directly.

Example

let a = 12u32;let b = 13u32;let result = if a > b { b - a } else { 0 };

Use instead:

let a = 12u32;let b = 13u32;let result = a.saturating_sub(b);
Applicability:MaybeIncorrect(?)
Added in:1.83.0
Related Issues
View Source

invisible_characters📋
correctnessdeny

What it does

Checks for invisible Unicode characters in the code.

Why is this bad?

Having an invisible character in the code makes for allsorts of April fools, but otherwise is very much frowned upon.

Example

You don’t see it, but there may be a zero-width space or soft hyphensome­where in this text.

Past names

  • zero_width_space
Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

io_other_error📋
stylewarn

This lint warns on callingio::Error::new(..) with a kind ofio::ErrorKind::Other.

Why is this bad?

Since Rust 1.74, there’s theio::Error::other(_) shortcut.

Example

use std::io;let _ = io::Error::new(io::ErrorKind::Other, "bad".to_string());

Use instead:

let _ = std::io::Error::other("bad".to_string());

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.87.0
Related Issues
View Source

ip_constant📋
pedanticallow

What it does

Checks for IP addresses that could be replaced with predefined constants such asIpv4Addr::new(127, 0, 0, 1) instead of using the appropriate constants.

Why is this bad?

Using specific IP addresses like127.0.0.1 or::1 is less clear and less maintainable than using thepredefined constantsIpv4Addr::LOCALHOST orIpv6Addr::LOCALHOST. These constants improve codereadability, make the intent explicit, and are less error-prone.

Example

use std::net::{Ipv4Addr, Ipv6Addr};// IPv4 loopbacklet addr_v4 = Ipv4Addr::new(127, 0, 0, 1);// IPv6 loopbacklet addr_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);

Use instead:

use std::net::{Ipv4Addr, Ipv6Addr};// IPv4 loopbacklet addr_v4 = Ipv4Addr::LOCALHOST;// IPv6 loopbacklet addr_v6 = Ipv6Addr::LOCALHOST;
Applicability:MachineApplicable(?)
Added in:1.89.0
Related Issues
View Source

is_digit_ascii_radix📋
stylewarn

What it does

Finds usages ofchar::is_digit thatcan be replaced withis_ascii_digit oris_ascii_hexdigit.

Why is this bad?

is_digit(..) is slower and requires specifying the radix.

Example

let c: char = '6';c.is_digit(10);c.is_digit(16);

Use instead:

let c: char = '6';c.is_ascii_digit();c.is_ascii_hexdigit();
Applicability:MachineApplicable(?)
Added in:1.62.0
Related Issues
View Source

items_after_statements📋
pedanticallow

What it does

Checks for items declared after some statement in a block.

Why is this bad?

Items live for the entire scope they are declaredin. But statements are processed in order. This might cause confusion asit’s hard to figure out which item is meant in a statement.

Example

fn foo() {    println!("cake");}fn main() {    foo(); // prints "foo"    fn foo() {        println!("foo");    }    foo(); // prints "foo"}

Use instead:

fn foo() {    println!("cake");}fn main() {    fn foo() {        println!("foo");    }    foo(); // prints "foo"    foo(); // prints "foo"}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

items_after_test_module📋
stylewarn

What it does

Triggers if an item is declared after the testing module marked with#[cfg(test)].

Why is this bad?

Having items declared after the testing module is confusing and may lead to bad test coverage.

Example

#[cfg(test)]mod tests {    // [...]}fn my_function() {    // [...]}

Use instead:

fn my_function() {    // [...]}#[cfg(test)]mod tests {    // [...]}
Applicability:MachineApplicable(?)
Added in:1.71.0
Related Issues
View Source

iter_cloned_collect📋
stylewarn

What it does

Checks for the use of.cloned().collect() on slice tocreate aVec.

Why is this bad?

.to_vec() is clearer

Example

let s = [1, 2, 3, 4, 5];let s2: Vec<isize> = s[..].iter().cloned().collect();

The better use would be:

let s = [1, 2, 3, 4, 5];let s2: Vec<isize> = s.to_vec();
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

iter_count📋
complexitywarn

What it does

Checks for the use of.iter().count().

Why is this bad?

.len() is more efficient and morereadable.

Example

let some_vec = vec![0, 1, 2, 3];some_vec.iter().count();&some_vec[..].iter().count();

Use instead:

let some_vec = vec![0, 1, 2, 3];some_vec.len();&some_vec[..].len();
Applicability:MachineApplicable(?)
Added in:1.52.0
Related Issues
View Source

iter_filter_is_ok📋
pedanticallow

What it does

Checks for usage of.filter(Result::is_ok) that may be replaced with a.flatten() call.This lint will require additional changes to the follow-up calls as it affects the type.

Why is this bad?

This pattern is often followed by manual unwrapping ofResult. The simplificationresults in more readable and succinct code without the need for manual unwrapping.

Example

vec![Ok::<i32, String>(1)].into_iter().filter(Result::is_ok);

Use instead:

vec![Ok::<i32, String>(1)].into_iter().flatten();
Applicability:HasPlaceholders(?)
Added in:1.77.0
Related Issues
View Source

iter_filter_is_some📋
pedanticallow

What it does

Checks for usage of.filter(Option::is_some) that may be replaced with a.flatten() call.This lint will require additional changes to the follow-up calls as it affects the type.

Why is this bad?

This pattern is often followed by manual unwrapping of theOption. The simplificationresults in more readable and succinct code without the need for manual unwrapping.

Example

vec![Some(1)].into_iter().filter(Option::is_some);

Use instead:

vec![Some(1)].into_iter().flatten();
Applicability:HasPlaceholders(?)
Added in:1.77.0
Related Issues
View Source

iter_kv_map📋
complexitywarn

What it does

Checks for iterating a map (HashMap orBTreeMap) andignoring either the keys or values.

Why is this bad?

Readability. There arekeys andvalues methods thatcan be used to express that we only need the keys or the values.

Example

let map: HashMap<u32, u32> = HashMap::new();let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>();

Use instead:

let map: HashMap<u32, u32> = HashMap::new();let values = map.values().collect::<Vec<_>>();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.66.0
Related Issues
View Source

iter_next_loop📋
correctnessdeny

What it does

Checks for loops onx.next().

Why is this bad?

next() returns eitherSome(value) if there was avalue, orNone otherwise. The insidious thing is thatOption<_>implementsIntoIterator, so that possibly one value will be iterated,leading to some hard to find bugs. No one will want to write such codeexcept to win an Underhanded RustContest.

Example

for x in y.next() {    ..}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

iter_next_slice📋
stylewarn

What it does

Checks for usage ofiter().next() on a Slice or an Array

Why is this bad?

These can be shortened into.get()

Example

a[2..].iter().next();b.iter().next();

should be written as:

a.get(2);b.get(0);
Applicability:MachineApplicable(?)
Added in:1.46.0
Related Issues
View Source

iter_not_returning_iterator📋
pedanticallow

What it does

Detects methods namediter oriter_mut that do not have a return type that implementsIterator.

Why is this bad?

Methods namediter oriter_mut conventionally return anIterator.

Example

// `String` does not implement `Iterator`struct Data {}impl Data {    fn iter(&self) -> String {        todo!()    }}

Use instead:

use std::str::Chars;struct Data {}impl Data {    fn iter(&self) -> Chars<'static> {        todo!()    }}
Applicability:Unspecified(?)
Added in:1.57.0
Related Issues
View Source

iter_nth📋
stylewarn

What it does

Checks for usage of.iter().nth()/.iter_mut().nth() on standard library types that haveequivalent.get()/.get_mut() methods.

Why is this bad?

.get() and.get_mut() are equivalent but more concise.

Example

let some_vec = vec![0, 1, 2, 3];let bad_vec = some_vec.iter().nth(3);let bad_slice = &some_vec[..].iter().nth(3);

The correct use would be:

let some_vec = vec![0, 1, 2, 3];let bad_vec = some_vec.get(3);let bad_slice = &some_vec[..].get(3);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

iter_nth_zero📋
stylewarn

What it does

Checks for the use ofiter.nth(0).

Why is this bad?

iter.next() is equivalent toiter.nth(0), as they both consume the next element,but is more readable.

Example

let x = s.iter().nth(0);

Use instead:

let x = s.iter().next();
Applicability:MachineApplicable(?)
Added in:1.42.0
Related Issues
View Source

iter_on_empty_collections📋
nurseryallow

What it does

Checks for calls toiter,iter_mut orinto_iter on empty collections

Why is this bad?

It is simpler to use the empty function from the standard library:

Example

use std::{slice, option};let a: slice::Iter<i32> = [].iter();let f: option::IntoIter<i32> = None.into_iter();

Use instead:

use std::iter;let a: iter::Empty<i32> = iter::empty();let b: iter::Empty<i32> = iter::empty();

Known problems

The type of the resulting iterator might become incompatible with its usage

Applicability:MaybeIncorrect(?)
Added in:1.65.0
Related Issues
View Source

iter_on_single_items📋
nurseryallow

What it does

Checks for calls toiter,iter_mut orinto_iter on collections containing a single item

Why is this bad?

It is simpler to use the once function from the standard library:

Example

let a = [123].iter();let b = Some(123).into_iter();

Use instead:

use std::iter;let a = iter::once(&123);let b = iter::once(123);

Known problems

The type of the resulting iterator might become incompatible with its usage

Applicability:MaybeIncorrect(?)
Added in:1.65.0
Related Issues
View Source

iter_out_of_bounds📋
suspiciouswarn

What it does

Looks for iterator combinator calls such as.take(x) or.skip(x)wherex is greater than the amount of items that an iterator will produce.

Why is this bad?

Taking or skipping more items than there are in an iterator either creates an iteratorwith all items from the original iterator or an iterator with no items at all.This is most likely not what the user intended to do.

Example

for _ in [1, 2, 3].iter().take(4) {}

Use instead:

for _ in [1, 2, 3].iter() {}
Applicability:Unspecified(?)
Added in:1.74.0
Related Issues
View Source

iter_over_hash_type📋
restrictionallow

What it does

This is a restriction lint which prevents the use of hash types (i.e.,HashSet andHashMap) in for loops.

Why restrict this?

Because hash types are unordered, when iterated through such as in afor loop, the values are returned inan 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 undesiredside effects.

Example

    let my_map = std::collections::HashMap::<i32, String>::new();    for (key, value) in my_map { /* ... */ }

Use instead:

    let my_map = std::collections::HashMap::<i32, String>::new();    let mut keys = my_map.keys().clone().collect::<Vec<_>>();    keys.sort();    for key in keys {        let value = &my_map[key];    }
Applicability:Unspecified(?)
Added in:1.76.0
Related Issues
View Source

iter_overeager_cloned📋
perfwarn

What it does

Checks for usage of_.cloned().<func>() where call to.cloned() can be postponed.

Why is this bad?

It’s often inefficient to clone all elements of an iterator, when eventually, only someof them will be consumed.

Known Problems

Thislint removes the side of effect of cloning items in the iterator.A code that relies on that side-effect could fail.

Examples

vec.iter().cloned().take(10);vec.iter().cloned().last();

Use instead:

vec.iter().take(10).cloned();vec.iter().last().cloned();
Applicability:MachineApplicable(?)
Added in:1.60.0
Related Issues
View Source

iter_skip_next📋
stylewarn

What it does

Checks for usage of.skip(x).next() on iterators.

Why is this bad?

.nth(x) is cleaner

Example

let some_vec = vec![0, 1, 2, 3];let bad_vec = some_vec.iter().skip(3).next();let bad_slice = &some_vec[..].iter().skip(3).next();

The correct use would be:

let some_vec = vec![0, 1, 2, 3];let bad_vec = some_vec.iter().nth(3);let bad_slice = &some_vec[..].iter().nth(3);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

iter_skip_zero📋
correctnessdeny

What it does

Checks for usage of.skip(0) on iterators.

Why is this bad?

This was likely intended to be.skip(1) to skip the first element, as.skip(0) doesnothing. If not, the call should be removed.

Example

let v = vec![1, 2, 3];let x = v.iter().skip(0).collect::<Vec<_>>();let y = v.iter().collect::<Vec<_>>();assert_eq!(x, y);
Applicability:MaybeIncorrect(?)
Added in:1.73.0
Related Issues
View Source

iter_with_drain📋
nurseryallow

What it does

Checks for usage of.drain(..) onVec andVecDeque for iteration.

Why is this bad?

.into_iter() is simpler with better performance.

Example

let mut foo = vec![0, 1, 2, 3];let bar: HashSet<usize> = foo.drain(..).collect();

Use instead:

let foo = vec![0, 1, 2, 3];let bar: HashSet<usize> = foo.into_iter().collect();
Applicability:MaybeIncorrect(?)
Added in:1.61.0
Related Issues
View Source

iter_without_into_iter📋
pedanticallow

What it does

Looks foriter anditer_mut methods without an associatedIntoIterator for (&|&mut) Type implementation.

Why is this bad?

It’s not bad, but having them is idiomatic and allows the type to be used in for loops directly(for val in &iter {}), without having to first calliter() oriter_mut().

Limitations

This lint focuses on providing an idiomatic API. Therefore, it will onlylint on types which are accessible outside of the crate. For internal types,theIntoIterator trait can be implemented on demand if it is actually needed.

Example

struct MySlice<'a>(&'a [u8]);impl<'a> MySlice<'a> {    pub fn iter(&self) -> std::slice::Iter<'a, u8> {        self.0.iter()    }}

Use instead:

struct MySlice<'a>(&'a [u8]);impl<'a> MySlice<'a> {    pub fn iter(&self) -> std::slice::Iter<'a, u8> {        self.0.iter()    }}impl<'a> IntoIterator for &MySlice<'a> {    type Item = &'a u8;    type IntoIter = std::slice::Iter<'a, u8>;    fn into_iter(self) -> Self::IntoIter {        self.iter()    }}
Applicability:Unspecified(?)
Added in:1.75.0
Related Issues
View Source

iterator_step_by_zero📋
correctnessdeny

What it does

Checks for calling.step_by(0) on iterators which panics.

Why is this bad?

This very much looks like an oversight. Usepanic!() instead if youactually intend to panic.

Example

for x in (0..100).step_by(0) {    //..}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

join_absolute_paths📋
suspiciouswarn

What it does

Checks for calls toPath::join that start with a path separator (\\ or/).

Why is this bad?

If the argument toPath::join starts with a separator, it will overwritethe original path. If this is intentional, prefer usingPath::new instead.

Note the behavior is platform dependent. A leading\\ will be acceptedon unix systems as part of the file name

SeePath::join

Example

let path = Path::new("/bin");let joined_path = path.join("/sh");assert_eq!(joined_path, PathBuf::from("/sh"));

Use instead;

let path = Path::new("/bin");// If this was unintentional, remove the leading separatorlet joined_path = path.join("sh");assert_eq!(joined_path, PathBuf::from("/bin/sh"));// If this was intentional, create a new path insteadlet new = Path::new("/sh");assert_eq!(new, PathBuf::from("/sh"));
Applicability:Unspecified(?)
Added in:1.76.0
Related Issues
View Source

just_underscores_and_digits📋
stylewarn

What it does

Checks if you have variables whose name consists of justunderscores and digits.

Why is this bad?

It’s hard to memorize what a variable means without adescriptive name.

Example

let _1 = 1;let ___1 = 1;let __1___2 = 11;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

large_const_arrays📋
perfwarn

What it does

Checks for largeconst arrays that shouldbe defined asstatic instead.

Why is this bad?

Performance: const variables are inlined upon use.Static items result in only one instance and has a fixed location in memory.

Example

pub const a = [0u32; 1_000_000];

Use instead:

pub static a = [0u32; 1_000_000];

Configuration

  • array-size-threshold: The maximum allowed size for arrays on the stack

    (default:16384)

Applicability:MachineApplicable(?)
Added in:1.44.0
Related Issues
View Source

large_digit_groups📋
pedanticallow

What it does

Warns if the digits of an integral or floating-pointconstant are grouped into groups thatare too large.

Why is this bad?

Negatively impacts readability.

Example

let x: u64 = 6186491_8973511;
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

large_enum_variant📋
perfwarn

What it does

Checks for large size differences between variants onenums.

Why is this bad?

Enum size is bounded by the largest variant. Having onelarge variant can penalize the memory layout of that enum.

Known problems

This lint obviously cannot take the distribution ofvariants in your running program into account. It is possible that thesmaller variants make up less than 1% of all instances, in which casethe overhead is negligible and the boxing is counter-productive. Alwaysmeasure the change this lint suggests.

For types that implementCopy, the suggestion toBox a variant’sdata would require removing the trait impl. The types can of coursestill beClone, but that is worse ergonomically. Depending on theuse case it may be possible to store the large data in an auxiliarystructure (e.g. Arena or ECS).

The lint will ignore the impact of generic types to the type layout byassuming every type parameter is zero-sized. Depending on your use case,this may lead to a false positive.

Example

enum Test {    A(i32),    B([i32; 8000]),}

Use instead:

// Possibly betterenum Test2 {    A(i32),    B(Box<[i32; 8000]>),}

Configuration

  • enum-variant-size-threshold: The maximum size of an enum’s variant to avoid box suggestion

    (default:200)

Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

large_futures📋
pedanticallow

What it does

It checks for the size of aFuture created byasync fn orasync {}.

Why is this bad?

Due to the currentunideal implementation ofCoroutine,large size of aFuture may cause stack overflows.

Example

async fn large_future(_x: [u8; 16 * 1024]) {}pub async fn trigger() {    large_future([0u8; 16 * 1024]).await;}

Box::pin the big future instead.

async fn large_future(_x: [u8; 16 * 1024]) {}pub async fn trigger() {    Box::pin(large_future([0u8; 16 * 1024])).await;}

Configuration

  • future-size-threshold: The maximum byte size aFuture can have, before it triggers theclippy::large_futures lint

    (default:16384)

Applicability:Unspecified(?)
Added in:1.70.0
Related Issues
View Source

large_include_file📋
restrictionallow

What it does

Checks for the inclusion of large files viainclude_bytes!()orinclude_str!().

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, ortemporarily to obtain a list of all large files.

Example

let included_str = include_str!("very_large_file.txt");let included_bytes = include_bytes!("very_large_file.txt");

Use instead:

use std::fs;// You can load the file at runtimelet string = fs::read_to_string("very_large_file.txt")?;let bytes = fs::read("very_large_file.txt")?;

Configuration

  • max-include-file-size: The maximum size of a file included viainclude_bytes!() orinclude_str!(), in bytes

    (default:1000000)

Applicability:Unspecified(?)
Added in:1.62.0
Related Issues
View Source

large_stack_arrays📋
pedanticallow

What it does

Checks for local arrays that may be too large.

Why is this bad?

Large local arrays may cause stack overflow.

Example

let a = [0u32; 1_000_000];

Configuration

  • array-size-threshold: The maximum allowed size for arrays on the stack

    (default:16384)

Applicability:Unspecified(?)
Added in:1.41.0
Related Issues
View Source

large_stack_frames📋
nurseryallow

What it does

Checks for functions that use a lot of stack space.

This often happens when constructing a large type, such as an array with a lot of elements,or constructingmany smaller-but-still-large structs, or copying around a lot of large types.

This lint is a more general version oflarge_stack_arraysthat is intended to look at functions as a whole instead of only individual array expressions inside of a function.

Why is this bad?

The stack region of memory is very limited in size (usuallymuch smaller than the heap) and attempting touse too much will result in a stack overflow and crash the program.To avoid this, you should consider allocating large types on the heap instead (e.g. by boxing them).

Keep in mind that the code path to construction of large types does not even need to be reachable;it purely needs toexist inside of the function to contribute to the stack size.For example, this causes a stack overflow even though the branch is unreachable:

fn main() {    if false {        let x = [0u8; 10000000]; // 10 MB stack array        black_box(&x);    }}

Known issues

False positives. The stack size that clippy sees is an estimated value and can be vastly differentfrom the actual stack usage after optimizations passes have run (especially true in release mode).Modern compilers are very smart and are able to optimize away a lot of unnecessary stack allocations.In debug mode however, it is usually more accurate.

This lint works by summing up the size of all variables that the user typed, variables that wereimplicitly introduced by the compiler for temporaries, function arguments and the return value,and comparing them against a (configurable, but high-by-default).

Example

This function creates four 500 KB arrays on the stack. Quite big but just small enough to not triggerlarge_stack_arrays.However, looking at the function as a whole, it’s clear that this uses a lot of stack space.

struct QuiteLargeType([u8; 500_000]);fn foo() {    // ... some function that uses a lot of stack space ...    let _x1 = QuiteLargeType([0; 500_000]);    let _x2 = QuiteLargeType([0; 500_000]);    let _x3 = QuiteLargeType([0; 500_000]);    let _x4 = QuiteLargeType([0; 500_000]);}

Instead of doing this, allocate the arrays on the heap.This currently requires going through aVec first and then converting it to aBox:

struct NotSoLargeType(Box<[u8]>);fn foo() {    let _x1 = NotSoLargeType(vec![0; 500_000].into_boxed_slice());//                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Now heap allocated.//                                                                The size of `NotSoLargeType` is 16 bytes.//  ...}

Configuration

  • stack-size-threshold: The maximum allowed stack size for functions in bytes

    (default:512000)

Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

large_types_passed_by_value📋
pedanticallow

What it does

Checks for functions taking arguments by value, wherethe argument type isCopy and large enough to be worth consideringpassing by reference. Does not trigger if the function is being exported,because that might induce API breakage, if the parameter is declared as mutable,or if the argument is aself.

Why is this bad?

Arguments passed by value might result in an unnecessaryshallow copy, taking up more space in the stack and requiring a call tomemcpy, which can be expensive.

Example

#[derive(Clone, Copy)]struct TooLarge([u8; 2048]);fn foo(v: TooLarge) {}

Use instead:

fn foo(v: &TooLarge) {}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

  • pass-by-value-size-limit: The minimum size (in bytes) to consider a type for passing by reference instead of by value.

    (default:256)

Applicability:MaybeIncorrect(?)
Added in:1.49.0
Related Issues
View Source

legacy_numeric_constants📋
stylewarn

What it does

Checks for usage of<integer>::max_value(),std::<integer>::MAX,std::<float>::EPSILON, etc.

Why is this bad?

All of these have been superseded by the associated constants on their respective types,such asi128::MAX. These legacy items may be deprecated in a future version of rust.

Example

let eps = std::f32::EPSILON;

Use instead:

let eps = f32::EPSILON;

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.79.0
Related Issues
View Source

len_without_is_empty📋
stylewarn

What it does

Checks for items that implement.len() but not.is_empty().

Why is this bad?

It is good custom to have both methods, because forsome data structures, asking about the length will be a costly operation,whereas.is_empty() can usually answer in constant time. Also it used tolead to false positives on thelen_zero lint – currently thatlint will ignore such entities.

Example

impl X {    pub fn len(&self) -> usize {        ..    }}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

len_zero📋
stylewarn

What it does

Checks for getting the length of something via.len()just to compare to zero, and suggests using.is_empty() where applicable.

Why is this bad?

Some structures can answer.is_empty() much fasterthan calculating their length. So it is good to get into the habit of using.is_empty(), and having it is cheap.Besides, it makes the intent clearer than a manual comparison in some contexts.

Example

if x.len() == 0 {    ..}if y.len() != 0 {    ..}

instead use

if x.is_empty() {    ..}if !y.is_empty() {    ..}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

let_and_return📋
stylewarn

What it does

Checks forlet-bindings, which are subsequentlyreturned.

Why is this bad?

It is just extraneous code. Remove it to make your codemore rusty.

Known problems

In the case of some temporaries, e.g. locks, eliding the variable binding could leadto deadlocks. Seethis issue.This could become relevant if the code is later changed to use the code that would have beenbound without first assigning it to a let-binding.

Example

fn foo() -> String {    let x = String::new();    x}

instead, use

fn foo() -> String {    String::new()}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

let_underscore_future📋
suspiciouswarn

What it does

Checks forlet _ = <expr> where the resulting type of expr implementsFuture

Why is this bad?

Futures must be polled for work to be done. The original intention was most likely to await the futureand ignore the resulting value.

Example

async fn foo() -> Result<(), ()> {    Ok(())}let _ = foo();

Use instead:

async fn foo() -> Result<(), ()> {    Ok(())}let _ = foo().await;
Applicability:Unspecified(?)
Added in:1.67.0
Related Issues
View Source

let_underscore_lock📋
correctnessdeny

What it does

Checks forlet _ = sync_lock. This supportsmutex andrwlock inparking_lot. Forstd locks see therustc lintlet_underscore_lock

Why is this bad?

This statement immediately drops the lock instead ofextending its lifetime to the end of the scope, which is often not intended.To extend lock lifetime to the end of the scope, use an underscore-prefixedname instead (i.e. _lock). If you want to explicitly drop the lock,std::mem::drop conveys your intention better and is less error-prone.

Example

let _ = mutex.lock();

Use instead:

let _lock = mutex.lock();
Applicability:Unspecified(?)
Added in:1.43.0
Related Issues
View Source

let_underscore_must_use📋
restrictionallow

What it does

Checks forlet _ = <expr> where expr is#[must_use]

Why restrict this?

To ensure that all#[must_use] types are used rather than ignored.

Example

fn f() -> Result<u32, u32> {    Ok(0)}let _ = f();// is_ok() is marked #[must_use]let _ = f().is_ok();
Applicability:Unspecified(?)
Added in:1.42.0
Related Issues
View Source

let_underscore_untyped📋
restrictionallow

What it does

Checks forlet _ = <expr> without a type annotation, and suggests to either provide one,or remove thelet keyword altogether.

Why restrict this?

Thelet _ = <expr> expression ignores the value of<expr>, but will continue to do so evenif the type were to change, thus potentially introducing subtle bugs. By supplying a typeannotation, one will be forced to re-visit the decision to ignore the value in such cases.

Known problems

The_ = <expr> is not properly supported by some tools (e.g. IntelliJ) and may seem oddto many developers. This lint also partially overlaps with the otherlet_underscore_*lints.

Example

fn foo() -> Result<u32, ()> {    Ok(123)}let _ = foo();

Use instead:

fn foo() -> Result<u32, ()> {    Ok(123)}// Either provide a type annotation:let _: Result<u32, ()> = foo();// …or drop the let keyword:_ = foo();
Applicability:Unspecified(?)
Added in:1.69.0
Related Issues
View Source

let_unit_value📋
stylewarn

What it does

Checks for binding a unit value.

Why is this bad?

A unit value cannot usefully be used anywhere. Sobinding one is kind of pointless.

Example

let x = {    1;};
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

let_with_type_underscore📋
complexitywarn

What it does

Detects when a variable is declared with an explicit type of_.

Why is this bad?

It adds noise,: _ provides zero clarity or utility.

Example

let my_number: _ = 1;

Use instead:

let my_number = 1;
Applicability:MachineApplicable(?)
Added in:1.70.0
Related Issues
View Source

lines_filter_map_ok📋
suspiciouswarn

What it does

Checks for usage oflines.filter_map(Result::ok) orlines.flat_map(Result::ok)whenlines has typestd::io::Lines.

Why is this bad?

Lines instances might produce a never-ending stream ofErr, in which casefilter_map(Result::ok) will enter an infinite loop while waiting for anOk variant. Callingnext() once is sufficient to enter the infinite loop,even in the absence of explicit loops in the user code.

This situation can arise when working with user-provided paths. On some platforms,std::fs::File::open(path) might returnOk(fs) even whenpath is a directory,but any later attempt to read fromfs will return an error.

Known problems

This lint suggests replacingfilter_map() orflat_map() applied to aLinesinstance in all cases. There are two cases where the suggestion might not beappropriate or necessary:

  • If theLines instance can never produce any error, or if an error is producedonly once just before terminating the iterator, usingmap_while() is notnecessary but will not do any harm.
  • If theLines instance can produce intermittent errors then recover and producesuccessful results, usingmap_while() would stop at the first error.

Example

let mut lines = BufReader::new(File::open("some-path")?).lines().filter_map(Result::ok);// If "some-path" points to a directory, the next statement never terminates:let first_line: Option<String> = lines.next();

Use instead:

let mut lines = BufReader::new(File::open("some-path")?).lines().map_while(Result::ok);let first_line: Option<String> = lines.next();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.70.0
Related Issues
View Source

linkedlist📋
pedanticallow

What it does

Checks for usage of anyLinkedList, suggesting to use aVec or aVecDeque (formerly calledRingBuf).

Why is this bad?

Gankra says:

The TL;DR ofLinkedList is that it’s built on a massive amount ofpointers and indirection.It wastes memory, it has terrible cache locality, and is all-around slow.RingBuf, while“only” amortized for push/pop, should be faster in the general case foralmost every possibleworkload, and isn’t even amortized at all if you can predict the capacityyou need.

LinkedLists are only really good if you’re doing a lot of merging orsplitting of lists.This is because they can just mangle some pointers instead of actuallycopying the data. Evenif you’re doing a lot of insertion in the middle of the list,RingBufcan still be betterbecause of how expensive it is to seek to the middle of aLinkedList.

Known problems

False positives – the instances where using aLinkedList makes sense are few and far between, but they can still happen.

Example

let x: LinkedList<usize> = LinkedList::new();

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

lint_groups_priority📋
correctnessdeny

What it does

Checks for lint groups with the same priority as lints in theCargo.toml[lints] table.

This lint will be removed oncecargo#12918is resolved.

Why is this bad?

The order of lints in the[lints] is ignored, to have a lint override a group thepriority field needs to be used, otherwise the sort order is undefined.

Known problems

Does not check lints inherited usinglints.workspace = true

Example

[lints.clippy]pedantic = "warn"similar_names = "allow"

Use instead:

[lints.clippy]pedantic = { level = "warn", priority = -1 }similar_names = "allow"
Applicability:Unspecified(?)
Added in:1.78.0
Related Issues
View Source

literal_string_with_formatting_args📋
nurseryallow

What it does

Checks if string literals have formatting arguments outside of macrosusing them (likeformat!).

Why is this bad?

It will likely not generate the expected content.

Example

let x: Option<usize> = None;let y = "hello";x.expect("{y:?}");

Use instead:

let x: Option<usize> = None;let y = "hello";x.expect(&format!("{y:?}"));
Applicability:Unspecified(?)
Added in:1.85.0
Related Issues
View Source

little_endian_bytes📋
restrictionallow

What it does

Checks for the usage of theto_le_bytes method and/or the functionfrom_le_bytes.

Why restrict this?

To ensure use of big-endian or the target’s endianness rather than little-endian.

Example

let _x = 2i32.to_le_bytes();let _y = 2i64.to_le_bytes();
Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

lossy_float_literal📋
restrictionallow

What it does

Checks for whole number float literals thatcannot be represented as the underlying type without loss.

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

let _: f32 = 16_777_217.0; // 16_777_216.0

Use instead:

let _: f32 = 16_777_216.0;let _: f64 = 16_777_217.0;
Applicability:MachineApplicable(?)
Added in:1.43.0
Related Issues
View Source

macro_metavars_in_unsafe📋
suspiciouswarn

What it does

Looks for macros that expand metavariables in an unsafe block.

Why is this bad?

This hides an unsafe block and allows the user of the macro to write unsafe code without an explicitunsafe block at callsite, making it possible to perform unsafe operations in seemingly safe code.

The macro should be restructured so that these metavariables are referenced outside of unsafe blocksand that the usual unsafety checks apply to the macro argument.

This is usually done by binding it to a variable outside of the unsafe blockand then using that variable inside of the block as shown in the example, or by referencing it a second timein a safe context, e.g.if false { $expr }.

Known limitations

Due to how macros are represented in the compiler at the time Clippy runs its lints,it’s not possible to look for metavariables in macro definitions directly.

Instead, this lint looks at expansions of macros.This leads to false negatives for macros that are never actually invoked.

By default, this lint is rather conservative and will only emit warnings on publicly-exportedmacros from the same crate, because oftentimes private internal macros are one-off macros wherethis lint would just be noise (e.g. macros that generateimpl blocks).The default behavior should help with preventing a high number of such false positives,however it can be configured to also emit warnings in private macros if desired.

Example

/// Gets the first element of a slicemacro_rules! first {    ($slice:expr) => {        unsafe {            let slice = $slice; // ⚠️ expansion inside of `unsafe {}`            assert!(!slice.is_empty());            // SAFETY: slice is checked to have at least one element            slice.first().unwrap_unchecked()        }    }}assert_eq!(*first!(&[1i32]), 1);// This will compile as a consequence (note the lack of `unsafe {}`)assert_eq!(*first!(std::hint::unreachable_unchecked() as &[i32]), 1);

Use instead:

macro_rules! first {    ($slice:expr) => {{        let slice = $slice; // ✅ outside of `unsafe {}`        unsafe {            assert!(!slice.is_empty());            // SAFETY: slice is checked to have at least one element            slice.first().unwrap_unchecked()        }    }}}assert_eq!(*first!(&[1]), 1);// This won't compile:assert_eq!(*first!(std::hint::unreachable_unchecked() as &[i32]), 1);

Configuration

  • warn-unsafe-macro-metavars-in-private-macros: Whether to also emit warnings for unsafe blocks with metavariable expansions inprivate macros.

    (default:false)

Applicability:Unspecified(?)
Added in:1.80.0
Related Issues
View Source

macro_use_imports📋
pedanticallow

What it does

Checks for#[macro_use] use....

Why is this bad?

Since the Rust 2018 edition you can importmacro’s directly, this is considered idiomatic.

Example

#[macro_use]extern crate some_crate;fn main() {    some_macro!();}

Use instead:

use some_crate::some_macro;fn main() {    some_macro!();}
Applicability:MaybeIncorrect(?)
Added in:1.44.0
Related Issues
View Source

main_recursion📋
stylewarn

What it does

Checks for recursion using the entrypoint.

Why is this bad?

Apart from special setups (which we could detect following attributes like #![no_std]),recursing into main() seems like an unintuitive anti-pattern we should be able to detect.

Example

fn main() {    main();}
Applicability:Unspecified(?)
Added in:1.38.0
Related Issues
View Source

manual_abs_diff📋
complexitywarn

What it does

Detects patterns likeif a > b { a - b } else { b - a } and suggests usinga.abs_diff(b).

Why is this bad?

Usingabs_diff is shorter, more readable, and avoids control flow.

Examples

if a > b {    a - b} else {    b - a}

Use instead:

a.abs_diff(b)

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.88.0
Related Issues
View Source

manual_assert📋
pedanticallow

What it does

Detectsif-then-panic! that can be replaced withassert!.

Why is this bad?

assert! is simpler thanif-then-panic!.

Example

let sad_people: Vec<&str> = vec![];if !sad_people.is_empty() {    panic!("there are sad people: {:?}", sad_people);}

Use instead:

let sad_people: Vec<&str> = vec![];assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
Applicability:MachineApplicable(?)
Added in:1.57.0
Related Issues
View Source

manual_async_fn📋
stylewarn

What it does

It checks for manual implementations ofasync functions.

Why is this bad?

It’s more idiomatic to use the dedicated syntax.

Example

use std::future::Future;fn foo() -> impl Future<Output = i32> { async { 42 } }

Use instead:

async fn foo() -> i32 { 42 }
Applicability:MachineApplicable(?)
Added in:1.45.0
Related Issues
View Source

manual_bits📋
stylewarn

What it does

Checks for usage ofsize_of::<T>() * 8 whenT::BITS is available.

Why is this bad?

Can be written as the shorterT::BITS.

Example

size_of::<usize>() * 8;

Use instead:

usize::BITS as usize;

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.60.0
Related Issues
View Source

manual_c_str_literals📋
complexitywarn

What it does

Checks for the manual creation of C strings (a string with aNUL byte at the end), eitherthrough one of theCStr constructor functions, or more plainly by calling.as_ptr()on a (byte) string literal with a hardcoded\0 byte at the end.

Why is this bad?

This can be written more concisely usingc"str" literals and is also less error-prone,because the compiler checks for interiorNUL bytes and the terminatingNUL byte is inserted automatically.

Example

fn needs_cstr(_: &CStr) {}needs_cstr(CStr::from_bytes_with_nul(b"Hello\0").unwrap());unsafe { libc::puts("World\0".as_ptr().cast()) }

Use instead:

fn needs_cstr(_: &CStr) {}needs_cstr(c"Hello");unsafe { libc::puts(c"World".as_ptr()) }

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.78.0
Related Issues
View Source

manual_clamp📋
complexitywarn

What it does

Identifies good opportunities for a clamp function from std or core, and suggests using it.

Why is this bad?

clamp is much shorter, easier to read, and doesn’t use any control flow.

Limitations

This lint will only trigger if max and min are known at compile time, and max isgreater than min.

Known issue(s)

If the clamped variable is NaN this suggestion will cause the code to propagate NaNrather than returning eithermax ormin.

clamp functions will panic ifmax < min,max.is_nan(), ormin.is_nan().Some may consider panicking in these situations to be desirable, but it also mayintroduce panicking where there wasn’t any before.

See alsothe discussion in thePR.

Examples

if input > max {    max} else if input < min {    min} else {    input}
input.max(min).min(max)
match input {    x if x > max => max,    x if x < min => min,    x => x,}
let mut x = input;if x < min { x = min; }if x > max { x = max; }

Use instead:

input.clamp(min, max)

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.66.0
Related Issues
View Source

manual_contains📋
perfwarn

What it does

Checks for usage ofiter().any() on slices when it can be replaced withcontains() and suggests doing so.

Why is this bad?

contains() is more concise and idiomatic, while also being faster in some cases.

Example

fn foo(values: &[u8]) -> bool {    values.iter().any(|&v| v == 10)}

Use instead:

fn foo(values: &[u8]) -> bool {    values.contains(&10)}
Applicability:MachineApplicable(?)
Added in:1.87.0
Related Issues
View Source

manual_dangling_ptr📋
stylewarn

What it does

Checks for casts of small constant literals ormem::align_of results to raw pointers.

Why is this bad?

This creates a dangling pointer and is better expressed as{std,core}::ptr::{dangling,dangling_mut}.

Example

let ptr = 4 as *const u32;let aligned = std::mem::align_of::<u32>() as *const u32;let mut_ptr: *mut i64 = 8 as *mut _;

Use instead:

let ptr = std::ptr::dangling::<u32>();let aligned = std::ptr::dangling::<u32>();let mut_ptr: *mut i64 = std::ptr::dangling_mut();
Applicability:MachineApplicable(?)
Added in:1.88.0
Related Issues
View Source

manual_div_ceil📋
complexitywarn

What it does

Checks for an expression like(x + (y - 1)) / y which is a common manual reimplementationofx.div_ceil(y).

Why is this bad?

It’s simpler, clearer and more readable.

Example

let x: i32 = 7;let y: i32 = 4;let div = (x + (y - 1)) / y;

Use instead:

#![feature(int_roundings)]let x: i32 = 7;let y: i32 = 4;let div = x.div_ceil(y);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.83.0
Related Issues
View Source

manual_filter📋
complexitywarn

What it does

Checks for usage ofmatch which could be implemented usingfilter

Why is this bad?

Using thefilter method is clearer and more concise.

Example

match Some(0) {    Some(x) => if x % 2 == 0 {                    Some(x)               } else {                    None                },    None => None,};

Use instead:

Some(0).filter(|&x| x % 2 == 0);
Applicability:MachineApplicable(?)
Added in:1.66.0
Related Issues
View Source

manual_filter_map📋
complexitywarn

What it does

Checks for usage of_.filter(_).map(_) that can be written more simplyasfilter_map(_).

Why is this bad?

Redundant code in thefilter andmap operations is poor style andless performant.

Example

(0_i32..10)    .filter(|n| n.checked_add(1).is_some())    .map(|n| n.checked_add(1).unwrap());

Use instead:

(0_i32..10).filter_map(|n| n.checked_add(1));

Past names

  • filter_map
Applicability:MachineApplicable(?)
Added in:1.51.0
Related Issues
View Source

manual_find📋
complexitywarn

What it does

Checks for manual implementations of Iterator::find

Why is this bad?

It doesn’t affect performance, but usingfind is shorter and easier to read.

Example

fn example(arr: Vec<i32>) -> Option<i32> {    for el in arr {        if el == 1 {            return Some(el);        }    }    None}

Use instead:

fn example(arr: Vec<i32>) -> Option<i32> {    arr.into_iter().find(|&el| el == 1)}
Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

manual_find_map📋
complexitywarn

What it does

Checks for usage of_.find(_).map(_) that can be written more simplyasfind_map(_).

Why is this bad?

Redundant code in thefind andmap operations is poor style andless performant.

Example

(0_i32..10)    .find(|n| n.checked_add(1).is_some())    .map(|n| n.checked_add(1).unwrap());

Use instead:

(0_i32..10).find_map(|n| n.checked_add(1));

Past names

  • find_map
Applicability:MachineApplicable(?)
Added in:1.51.0
Related Issues
View Source

manual_flatten📋
complexitywarn

What it does

Checks for unnecessaryif let usage in a for loopwhere only theSome orOk variant of the iterator element is used.

Why is this bad?

It is verbose and can be simplifiedby first calling theflatten method on theIterator.

Example

let x = vec![Some(1), Some(2), Some(3)];for n in x {    if let Some(n) = n {        println!("{}", n);    }}

Use instead:

let x = vec![Some(1), Some(2), Some(3)];for n in x.into_iter().flatten() {    println!("{}", n);}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.52.0
Related Issues
View Source

manual_hash_one📋
complexitywarn

What it does

Checks for cases whereBuildHasher::hash_one can be used.

Why is this bad?

It is more concise to use thehash_one method.

Example

use std::hash::{BuildHasher, Hash, Hasher};use std::collections::hash_map::RandomState;let s = RandomState::new();let value = vec![1, 2, 3];let mut hasher = s.build_hasher();value.hash(&mut hasher);let hash = hasher.finish();

Use instead:

use std::hash::BuildHasher;use std::collections::hash_map::RandomState;let s = RandomState::new();let value = vec![1, 2, 3];let hash = s.hash_one(&value);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.75.0
Related Issues
View Source

manual_ignore_case_cmp📋
perfwarn

What it does

Checks for manual case-insensitive ASCII comparison.

Why is this bad?

Theeq_ignore_ascii_case method is faster because it does not allocatememory for the new strings, and it is more readable.

Example

fn compare(a: &str, b: &str) -> bool {    a.to_ascii_lowercase() == b.to_ascii_lowercase() || a.to_ascii_lowercase() == "abc"}

Use instead:

fn compare(a: &str, b: &str) -> bool {    a.eq_ignore_ascii_case(b) || a.eq_ignore_ascii_case("abc")}
Applicability:MachineApplicable(?)
Added in:1.84.0
Related Issues
View Source

manual_inspect📋
complexitywarn

What it does

Checks for uses ofmap which return the original item.

Why is this bad?

inspect is both clearer in intent and shorter.

Example

let x = Some(0).map(|x| { println!("{x}"); x });

Use instead:

let x = Some(0).inspect(|x| println!("{x}"));
Applicability:MachineApplicable(?)
Added in:1.81.0
Related Issues
View Source

manual_instant_elapsed📋
pedanticallow

What it does

Lints subtraction betweenInstant::now() and anotherInstant.

Why is this bad?

It is easy to accidentally writeprev_instant - Instant::now(), which will always be 0nsasInstant subtraction saturates.

prev_instant.elapsed() also more clearly signals intention.

Example

use std::time::Instant;let prev_instant = Instant::now();let duration = Instant::now() - prev_instant;

Use instead:

use std::time::Instant;let prev_instant = Instant::now();let duration = prev_instant.elapsed();
Applicability:MachineApplicable(?)
Added in:1.65.0
Related Issues
View Source

manual_is_ascii_check📋
stylewarn

What it does

Suggests to use dedicated built-in methods,is_ascii_(lowercase|uppercase|digit|hexdigit) for checking on correspondingascii range

Why is this bad?

Using the built-in functions is more readable and makes itclear that it’s not a specific subset of characters, but allASCII (lowercase|uppercase|digit|hexdigit) characters.

Example

fn main() {    assert!(matches!('x', 'a'..='z'));    assert!(matches!(b'X', b'A'..=b'Z'));    assert!(matches!('2', '0'..='9'));    assert!(matches!('x', 'A'..='Z' | 'a'..='z'));    assert!(matches!('C', '0'..='9' | 'a'..='f' | 'A'..='F'));    ('0'..='9').contains(&'0');    ('a'..='z').contains(&'a');    ('A'..='Z').contains(&'A');}

Use instead:

fn main() {    assert!('x'.is_ascii_lowercase());    assert!(b'X'.is_ascii_uppercase());    assert!('2'.is_ascii_digit());    assert!('x'.is_ascii_alphabetic());    assert!('C'.is_ascii_hexdigit());    '0'.is_ascii_digit();    'a'.is_ascii_lowercase();    'A'.is_ascii_uppercase();}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.67.0
Related Issues
View Source

manual_is_finite📋
stylewarn

What it does

Checks for manualis_finite reimplementations(i.e.,x != <float>::INFINITY && x != <float>::NEG_INFINITY).

Why is this bad?

The methodis_finite is shorter and more readable.

Example

if x != f32::INFINITY && x != f32::NEG_INFINITY {}if x.abs() < f32::INFINITY {}

Use instead:

if x.is_finite() {}if x.is_finite() {}
Applicability:MaybeIncorrect(?)
Added in:1.73.0
Related Issues
View Source

manual_is_infinite📋
stylewarn

What it does

Checks for manualis_infinite reimplementations(i.e.,x == <float>::INFINITY || x == <float>::NEG_INFINITY).

Why is this bad?

The methodis_infinite is shorter and more readable.

Example

if x == f32::INFINITY || x == f32::NEG_INFINITY {}

Use instead:

if x.is_infinite() {}
Applicability:MachineApplicable(?)
Added in:1.73.0
Related Issues
View Source

manual_is_multiple_of📋
complexitywarn

What it does

Checks for manual implementation of.is_multiple_of() onunsigned integer types.

Why is this bad?

a.is_multiple_of(b) is a clearer way to check for divisibilityofa byb. This expression can never panic.

Example

if a % b == 0 {    println!("{a} is divisible by {b}");}

Use instead:

if a.is_multiple_of(b) {    println!("{a} is divisible by {b}");}
Applicability:MachineApplicable(?)
Added in:1.90.0
Related Issues
View Source

manual_is_power_of_two📋
pedanticallow

What it does

Checks for expressions likex.count_ones() == 1 orx & (x - 1) == 0, with x and unsigned integer, which may be manualreimplementations ofx.is_power_of_two().

Why is this bad?

Manual reimplementations ofis_power_of_two increase code complexity for little benefit.

Example

let a: u32 = 4;let result = a.count_ones() == 1;

Use instead:

let a: u32 = 4;let result = a.is_power_of_two();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.83.0
Related Issues
View Source

manual_is_variant_and📋
pedanticallow

What it does

Checks for usage ofoption.map(f).unwrap_or_default() andresult.map(f).unwrap_or_default() where f is a function or closure that returns thebool type.Also checks for equality comparisons likeoption.map(f) == Some(true) andresult.map(f) == Ok(true).

Why is this bad?

Readability. These can be written more concisely asoption.is_some_and(f) andresult.is_ok_and(f).

Example

option.map(|a| a > 10).unwrap_or_default();result.map(|a| a > 10).unwrap_or_default();option.map(|a| a > 10) == Some(true);result.map(|a| a > 10) == Ok(true);option.map(|a| a > 10) != Some(true);result.map(|a| a > 10) != Ok(true);

Use instead:

option.is_some_and(|a| a > 10);result.is_ok_and(|a| a > 10);option.is_some_and(|a| a > 10);result.is_ok_and(|a| a > 10);option.is_none_or(|a| a > 10);!result.is_ok_and(|a| a > 10);
Applicability:MachineApplicable(?)
Added in:1.77.0
Related Issues
View Source

manual_let_else📋
pedanticallow

What it does

Warn of cases wherelet...else could be used

Why is this bad?

let...else provides a standard construct for this patternthat people can easily recognize. It’s also more compact.

Example

let v = if let Some(v) = w { v } else { return };

Could be written:

let Some(v) = w else { return };

Configuration

  • matches-for-let-else: Whether the matches should be considered by the lint, and whether there shouldbe filtering for common types.

    (default:"WellKnownTypes")

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:HasPlaceholders(?)
Added in:1.67.0
Related Issues
View Source

manual_main_separator_str📋
complexitywarn

What it does

Checks for references onstd::path::MAIN_SEPARATOR.to_string() usedto build a&str.

Why is this bad?

There exists astd::path::MAIN_SEPARATOR_STR which does not requirean extra memory allocation.

Example

let s: &str = &std::path::MAIN_SEPARATOR.to_string();

Use instead:

let s: &str = std::path::MAIN_SEPARATOR_STR;
Applicability:MachineApplicable(?)
Added in:1.70.0
Related Issues
View Source

manual_map📋
stylewarn

What it does

Checks for usage ofmatch which could be implemented usingmap

Why is this bad?

Using themap method is clearer and more concise.

Example

match Some(0) {    Some(x) => Some(x + 1),    None => None,};

Use instead:

Some(0).map(|x| x + 1);
Applicability:MachineApplicable(?)
Added in:1.52.0
Related Issues
View Source

manual_memcpy📋
perfwarn

What it does

Checks for for-loops that manually copy items betweenslices that could be optimized by having a memcpy.

Why is this bad?

It is not as fast as a memcpy.

Example

for i in 0..src.len() {    dst[i + 64] = src[i];}

Use instead:

dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

manual_midpoint📋
pedanticallow

What it does

Checks for manual implementation ofmidpoint.

Why is this bad?

Using(x + y) / 2 might cause an overflow on the intermediateaddition result.

Example

let c = (a + 10) / 2;

Use instead:

let c = u32::midpoint(a, 10);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.87.0
Related Issues
View Source

manual_next_back📋
stylewarn

What it does

Checks for.rev().next() on aDoubleEndedIterator

Why is this bad?

.next_back() is cleaner.

Example

foo.iter().rev().next();

Use instead:

foo.iter().next_back();
Applicability:MachineApplicable(?)
Added in:1.71.0
Related Issues
View Source

manual_non_exhaustive📋
stylewarn

What it does

Checks for manual implementations of the non-exhaustive pattern.

Why is this bad?

Using the #[non_exhaustive] attribute expresses better the intentand allows possible optimizations when applied to enums.

Example

struct S {    pub a: i32,    pub b: i32,    _c: (),}enum E {    A,    B,    #[doc(hidden)]    _C,}struct T(pub i32, pub i32, ());

Use instead:

#[non_exhaustive]struct S {    pub a: i32,    pub b: i32,}#[non_exhaustive]enum E {    A,    B,}#[non_exhaustive]struct T(pub i32, pub i32);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.45.0
Related Issues
View Source

manual_ok_err📋
complexitywarn

What it does

Checks for manual implementation of.ok() or.err()onResult values.

Why is this bad?

Using.ok() or.err() rather than amatch orif let is less complex and more readable.

Example

let a = match func() {    Ok(v) => Some(v),    Err(_) => None,};let b = if let Err(v) = func() {    Some(v)} else {    None};

Use instead:

let a = func().ok();let b = func().err();
Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

manual_ok_or📋
stylewarn

What it does

Finds patterns that reimplementOption::ok_or.

Why is this bad?

Concise code helps focusing on behavior instead of boilerplate.

Examples

let foo: Option<i32> = None;foo.map_or(Err("error"), |v| Ok(v));

Use instead:

let foo: Option<i32> = None;foo.ok_or("error");
Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

manual_option_as_slice📋
complexitywarn

What it does

This detects various manual reimplementations ofOption::as_slice.

Why is this bad?

Those implementations are both more complex than callingas_sliceand unlike that incur a branch, pessimizing performance and leadingto more generated code.

Example

_ = opt.as_ref().map_or(&[][..], std::slice::from_ref);_ = match opt.as_ref() {    Some(f) => std::slice::from_ref(f),    None => &[],};

Use instead:

_ = opt.as_slice();_ = opt.as_slice();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

manual_pattern_char_comparison📋
stylewarn

What it does

Checks for manualchar comparison in string patterns

Why is this bad?

This can be written more concisely using achar or an array ofchar.This is more readable and more optimized when comparing to only onechar.

Example

"Hello World!".trim_end_matches(|c| c == '.' || c == ',' || c == '!' || c == '?');

Use instead:

"Hello World!".trim_end_matches(['.', ',', '!', '?']);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.81.0
Related Issues
View Source

manual_range_contains📋
stylewarn

What it does

Checks for expressions likex >= 3 && x < 8 that couldbe more readably expressed as(3..8).contains(x).

Why is this bad?

contains expresses the intent better and has lessfailure modes (such as fencepost errors or using|| instead of&&).

Example

// givenlet x = 6;assert!(x >= 3 && x < 8);

Use instead:

assert!((3..8).contains(&x));

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

manual_range_patterns📋
complexitywarn

What it does

Looks for combined OR patterns that are all contained in a specific range,e.g.6 | 4 | 5 | 9 | 7 | 8 can be rewritten as4..=9.

Why is this bad?

Using an explicit range is more concise and easier to read.

Known issues

This lint intentionally does not handle numbers greater thani128::MAX foru128 literalsin order to support negative numbers.

Example

let x = 6;let foo = matches!(x, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10);

Use instead:

let x = 6;let foo = matches!(x, 1..=10);
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

manual_rem_euclid📋
complexitywarn

What it does

Checks for an expression like((x % 4) + 4) % 4 which is a common manual reimplementationofx.rem_euclid(4).

Why is this bad?

It’s simpler and more readable.

Example

let x: i32 = 24;let rem = ((x % 4) + 4) % 4;

Use instead:

let x: i32 = 24;let rem = x.rem_euclid(4);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

manual_repeat_n📋
stylewarn

What it does

Checks forrepeat().take() that can be replaced withrepeat_n().

Why is this bad?

Usingrepeat_n() is more concise and clearer. Also,repeat_n() is sometimes faster thanrepeat().take() when the type of the element is non-trivial to clone because the original value can be reused for the last.next() call rather than always cloning.

Example

let _ = std::iter::repeat(10).take(3);

Use instead:

let _ = std::iter::repeat_n(10, 3);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

manual_retain📋
perfwarn

What it does

Checks for code to be replaced by.retain().

Why is this bad?

.retain() is simpler and avoids needless allocation.

Example

let mut vec = vec![0, 1, 2];vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();vec = vec.into_iter().filter(|x| x % 2 == 0).collect();

Use instead:

let mut vec = vec![0, 1, 2];vec.retain(|x| x % 2 == 0);vec.retain(|x| x % 2 == 0);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

manual_rotate📋
stylewarn

What it does

It detects manual bit rotations that could be rewritten using standardfunctionsrotate_left orrotate_right.

Why is this bad?

Calling the function better conveys the intent.

Known issues

Currently, the lint only catches shifts by constant amount.

Example

let x = 12345678_u32;let _ = (x >> 8) | (x << 24);

Use instead:

let x = 12345678_u32;let _ = x.rotate_right(8);
Applicability:MachineApplicable(?)
Added in:1.81.0
Related Issues
View Source

manual_saturating_arithmetic📋
stylewarn

What it does

Checks for.checked_add/sub(x).unwrap_or(MAX/MIN).

Why is this bad?

These can be written simply withsaturating_add/sub methods.

Example

let add = x.checked_add(y).unwrap_or(u32::MAX);let sub = x.checked_sub(y).unwrap_or(u32::MIN);

can be written using dedicated methods for saturating addition/subtraction as:

let add = x.saturating_add(y);let sub = x.saturating_sub(y);
Applicability:MachineApplicable(?)
Added in:1.39.0
Related Issues
View Source

manual_slice_fill📋
stylewarn

What it does

Checks for manually filling a slice with a value.

Why is this bad?

Using thefill method is more idiomatic and concise.

Example

let mut some_slice = [1, 2, 3, 4, 5];for i in 0..some_slice.len() {    some_slice[i] = 0;}

Use instead:

let mut some_slice = [1, 2, 3, 4, 5];some_slice.fill(0);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.86.0
Related Issues
View Source

manual_slice_size_calculation📋
complexitywarn

What it does

Whena is&[T], detecta.len() * size_of::<T>() and suggestsize_of_val(a)instead.

Why is this better?

  • Shorter to write
  • Removes the need for the human and the compiler to worry about overflow in themultiplication
  • Potentially faster at runtime as rust emits special no-wrapping flags when itcalculates the byte length
  • Less turbofishing

Example

let newlen = data.len() * size_of::<i32>();

Use instead:

let newlen = size_of_val(data);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.70.0
Related Issues
View Source

manual_split_once📋
complexitywarn

What it does

Checks for usage ofstr::splitn(2, _)

Why is this bad?

split_once is both clearer in intent and slightly more efficient.

Example

let s = "key=value=add";let (key, value) = s.splitn(2, '=').next_tuple()?;let value = s.splitn(2, '=').nth(1)?;let mut parts = s.splitn(2, '=');let key = parts.next()?;let value = parts.next()?;

Use instead:

let s = "key=value=add";let (key, value) = s.split_once('=')?;let value = s.split_once('=')?.1;let (key, value) = s.split_once('=')?;

Limitations

The multiple statement variant currently only detectsiter.next()?/iter.next().unwrap()in two separatelet statements that immediately follow thesplitn()

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.57.0
Related Issues
View Source

manual_str_repeat📋
perfwarn

What it does

Checks for manual implementations ofstr::repeat

Why is this bad?

These are both harder to read, as well as less performant.

Example

let x: String = std::iter::repeat('x').take(10).collect();

Use instead:

let x: String = "x".repeat(10);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.54.0
Related Issues
View Source

manual_string_new📋
pedanticallow

What it does

Checks for usage of"" to create aString, such as"".to_string(),"".to_owned(),String::from("") and others.

Why is this bad?

Different ways of creating an empty string makes your code less standardized, which canbe confusing.

Example

let a = "".to_string();let b: String = "".into();

Use instead:

let a = String::new();let b = String::new();
Applicability:MachineApplicable(?)
Added in:1.65.0
Related Issues
View Source

manual_strip📋
complexitywarn

What it does

Suggests usingstrip_{prefix,suffix} overstr::{starts,ends}_with and slicing usingthe pattern’s length.

Why is this bad?

Usingstr:strip_{prefix,suffix} is safer and may have better performance as there is noslicing which may panic and the compiler does not need to insert this panic code. It isalso sometimes more readable as it removes the need for duplicating or storing the patternused bystr::{starts,ends}_with and in the slicing.

Example

let s = "hello, world!";if s.starts_with("hello, ") {    assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");}

Use instead:

let s = "hello, world!";if let Some(end) = s.strip_prefix("hello, ") {    assert_eq!(end.to_uppercase(), "WORLD!");}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.48.0
Related Issues
View Source

manual_swap📋
complexitywarn

What it does

Checks for manual swapping.

Note that the lint will not be emitted in const blocks, as the suggestion would not be applicable.

Why is this bad?

Thestd::mem::swap function exposes the intent betterwithout deinitializing or copying either variable.

Example

let mut a = 42;let mut b = 1337;let t = b;b = a;a = t;

Use std::mem::swap():

let mut a = 1;let mut b = 2;std::mem::swap(&mut a, &mut b);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

manual_try_fold📋
perfwarn

What it does

Checks for usage ofIterator::fold with a type that implementsTry.

Why is this bad?

The code should usetry_fold instead, which short-circuits on failure, thus opening thedoor for additional optimizations not possible withfold as rustc can guarantee thefunction is never called onNone,Err, etc., alleviating otherwise necessary checks. It’salso slightly more idiomatic.

Known issues

This lint doesn’t take into account whether a function does something on the failure case,i.e., whether short-circuiting will affect behavior. Refactoring totry_fold is notdesirable in those cases.

Example

vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i));

Use instead:

vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i));

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:HasPlaceholders(?)
Added in:1.72.0
Related Issues
View Source

manual_unwrap_or📋
complexitywarn

What it does

Finds patterns that reimplementOption::unwrap_or orResult::unwrap_or.

Why is this bad?

Concise code helps focusing on behavior instead of boilerplate.

Example

let foo: Option<i32> = None;match foo {    Some(v) => v,    None => 1,};

Use instead:

let foo: Option<i32> = None;foo.unwrap_or(1);
Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

manual_unwrap_or_default📋
suspiciouswarn

What it does

Checks if amatch orif let expression can be simplified using.unwrap_or_default().

Why is this bad?

It can be done in one call with.unwrap_or_default().

Example

let x: Option<String> = Some(String::new());let y: String = match x {    Some(v) => v,    None => String::new(),};let x: Option<Vec<String>> = Some(Vec::new());let y: Vec<String> = if let Some(v) = x {    v} else {    Vec::new()};

Use instead:

let x: Option<String> = Some(String::new());let y: String = x.unwrap_or_default();let x: Option<Vec<String>> = Some(Vec::new());let y: Vec<String> = x.unwrap_or_default();
Applicability:MachineApplicable(?)
Added in:1.79.0
Related Issues
View Source

manual_while_let_some📋
stylewarn

What it does

Looks for loops that check for emptiness of aVec in the condition and pop an elementin the body as a separate operation.

Why is this bad?

Such loops can be written in a more idiomatic way by using a while-let loop and directlypattern matching on the return value ofVec::pop().

Example

let mut numbers = vec![1, 2, 3, 4, 5];while !numbers.is_empty() {    let number = numbers.pop().unwrap();    // use `number`}

Use instead:

let mut numbers = vec![1, 2, 3, 4, 5];while let Some(number) = numbers.pop() {    // use `number`}
Applicability:MachineApplicable(?)
Added in:1.71.0
Related Issues
View Source

many_single_char_names📋
pedanticallow

What it does

Checks for too many variables whose name consists of asingle character.

Why is this bad?

It’s hard to memorize what a variable means without adescriptive name.

Example

let (a, b, c, d, e, f, g) = (...);

Configuration

  • single-char-binding-names-threshold: The maximum number of single char bindings a scope may have

    (default:4)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

map_all_any_identity📋
complexitywarn

What it does

Checks for usage of.map(…), followed by.all(identity) or.any(identity).

Why is this bad?

The.all(…) or.any(…) methods can be called directly in place of.map(…).

Example

let e1 = v.iter().map(|s| s.is_empty()).all(|a| a);let e2 = v.iter().map(|s| s.is_empty()).any(std::convert::identity);

Use instead:

let e1 = v.iter().all(|s| s.is_empty());let e2 = v.iter().any(|s| s.is_empty());
Applicability:MachineApplicable(?)
Added in:1.84.0
Related Issues
View Source

map_clone📋
stylewarn

What it does

Checks for usage ofmap(|x| x.clone()) ordereferencing closures forCopy types, onIterator orOption,and suggestscloned() orcopied() instead

Why is this bad?

Readability, this can be written more concisely

Example

let x = vec![42, 43];let y = x.iter();let z = y.map(|i| *i);

The correct use would be:

let x = vec![42, 43];let y = x.iter();let z = y.cloned();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

map_collect_result_unit📋
stylewarn

What it does

Checks for usage of_.map(_).collect::<Result<(), _>().

Why is this bad?

Usingtry_for_each instead is more readable and idiomatic.

Example

(0..3).map(|t| Err(t)).collect::<Result<(), _>>();

Use instead:

(0..3).try_for_each(|t| Err(t));
Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

map_entry📋
perfwarn

What it does

Checks for usage ofcontains_key +insert onHashMaporBTreeMap.

Why is this bad?

Usingentry is more efficient.

Known problems

The suggestion may have type inference errors in some cases. e.g.

let mut map = std::collections::HashMap::new();let _ = if !map.contains_key(&0) {    map.insert(0, 0)} else {    None};

Example

if !map.contains_key(&k) {    map.insert(k, v);}

Use instead:

map.entry(k).or_insert(v);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

map_err_ignore📋
restrictionallow

What it does

Checks for instances ofmap_err(|_| Some::Enum)

Why restrict this?

Thismap_err throws away the original error rather than allowing the enum tocontain and report the cause of the error.

Example

Before:

use std::fmt;#[derive(Debug)]enum Error {    Indivisible,    Remainder(u8),}impl fmt::Display for Error {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        match self {            Error::Indivisible => write!(f, "could not divide input by three"),            Error::Remainder(remainder) => write!(                f,                "input is not divisible by three, remainder = {}",                remainder            ),        }    }}impl std::error::Error for Error {}fn divisible_by_3(input: &str) -> Result<(), Error> {    input        .parse::<i32>()        .map_err(|_| Error::Indivisible)        .map(|v| v % 3)        .and_then(|remainder| {            if remainder == 0 {                Ok(())            } else {                Err(Error::Remainder(remainder as u8))            }        })}

After:

use std::{fmt, num::ParseIntError};#[derive(Debug)]enum Error {    Indivisible(ParseIntError),    Remainder(u8),}impl fmt::Display for Error {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        match self {            Error::Indivisible(_) => write!(f, "could not divide input by three"),            Error::Remainder(remainder) => write!(                f,                "input is not divisible by three, remainder = {}",                remainder            ),        }    }}impl std::error::Error for Error {    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {        match self {            Error::Indivisible(source) => Some(source),            _ => None,        }    }}fn divisible_by_3(input: &str) -> Result<(), Error> {    input        .parse::<i32>()        .map_err(Error::Indivisible)        .map(|v| v % 3)        .and_then(|remainder| {            if remainder == 0 {                Ok(())            } else {                Err(Error::Remainder(remainder as u8))            }        })}
Applicability:Unspecified(?)
Added in:1.48.0
Related Issues
View Source

map_flatten📋
complexitywarn

What it does

Checks for usage of_.map(_).flatten(_) onIterator andOption

Why is this bad?

Readability, this can be written more concisely as_.flat_map(_) forIterator or_.and_then(_) forOption

Example

let vec = vec![vec![1]];let opt = Some(5);vec.iter().map(|x| x.iter()).flatten();opt.map(|x| Some(x * 2)).flatten();

Use instead:

vec.iter().flat_map(|x| x.iter());opt.and_then(|x| Some(x * 2));
Applicability:MachineApplicable(?)
Added in:1.31.0
Related Issues
View Source

map_identity📋
complexitywarn

What it does

Checks for instances ofmap(f) wheref is the identity function.

Why is this bad?

It can be written more concisely without the call tomap.

Example

let x = [1, 2, 3];let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();

Use instead:

let x = [1, 2, 3];let y: Vec<_> = x.iter().map(|x| 2*x).collect();
Applicability:MachineApplicable(?)
Added in:1.47.0
Related Issues
View Source

map_unwrap_or📋
pedanticallow

What it does

Checks for usage ofoption.map(_).unwrap_or(_) oroption.map(_).unwrap_or_else(_) orresult.map(_).unwrap_or_else(_).

Why is this bad?

Readability, these can be written more concisely (resp.) asoption.map_or(_, _),option.map_or_else(_, _) andresult.map_or_else(_, _).

Known problems

The order of the arguments is not in execution order

Examples

option.map(|a| a + 1).unwrap_or(0);option.map(|a| a > 10).unwrap_or(false);result.map(|a| a + 1).unwrap_or_else(some_function);

Use instead:

option.map_or(0, |a| a + 1);option.is_some_and(|a| a > 10);result.map_or_else(some_function, |a| a + 1);

Past names

  • option_map_unwrap_or
  • option_map_unwrap_or_else
  • result_map_unwrap_or_else

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.45.0
Related Issues
View Source

map_with_unused_argument_over_ranges📋
restrictionallow

What it does

Checks forIterator::map over ranges without using the parameter whichcould be more clearly expressed usingstd::iter::repeat(...).take(...)orstd::iter::repeat_n.

Why is this bad?

It expresses the intent more clearly totake the correct number of timesfrom a generating function than to apply a closure to each number in arange only to discard them.

Example

let random_numbers : Vec<_> = (0..10).map(|_| { 3 + 1 }).collect();

Use instead:

let f : Vec<_> = std::iter::repeat( 3 + 1 ).take(10).collect();

Known Issues

This lint may suggest replacing aMap<Range> with aTake<RepeatWith>.The former implements some traits that the latter does not, such asDoubleEndedIterator.

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.84.0
Related Issues
View Source

match_as_ref📋
complexitywarn

What it does

Checks for match which is used to add a reference to anOption value.

Why is this bad?

Usingas_ref() oras_mut() instead is shorter.

Example

let x: Option<()> = None;let r: Option<&()> = match x {    None => None,    Some(ref v) => Some(v),};

Use instead:

let x: Option<()> = None;let r: Option<&()> = x.as_ref();
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

match_bool📋
pedanticallow

What it does

Checks for matches where match expression is abool. Itsuggests to replace the expression with anif...else block.

Why is this bad?

It makes the code less readable.

Example

let condition: bool = true;match condition {    true => foo(),    false => bar(),}

Use if/else instead:

let condition: bool = true;if condition {    foo();} else {    bar();}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

match_like_matches_macro📋
stylewarn

What it does

Checks formatch orif let expressions producing abool that could be written usingmatches!

Why is this bad?

Readability and needless complexity.

Known problems

This lint falsely triggers, if there are arms withcfg attributes that remove an arm evaluating tofalse.

Example

let x = Some(5);let a = match x {    Some(0) => true,    _ => false,};let a = if let Some(0) = x {    true} else {    false};

Use instead:

let x = Some(5);let a = matches!(x, Some(0));

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.47.0
Related Issues
View Source

match_on_vec_items📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

clippy::indexing_slicing covers indexing and slicing onVec<_>.

Applicability:Unspecified(?)
Deprecated in:1.88.0
Related Issues

match_overlapping_arm📋
stylewarn

What it does

Checks for overlapping match arms.

Why is this bad?

It is likely to be an error and if not, makes the codeless obvious.

Example

let x = 5;match x {    1..=10 => println!("1 ... 10"),    5..=15 => println!("5 ... 15"),    _ => (),}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

match_ref_pats📋
stylewarn

What it does

Checks for matches where all arms match a reference,suggesting to remove the reference and deref the matched expressioninstead. It also checks forif let &foo = bar blocks.

Why is this bad?

It just makes the code less readable. That referencedestructuring adds nothing to the code.

Example

match x {    &A(ref y) => foo(y),    &B => bar(),    _ => frob(&x),}

Use instead:

match *x {    A(ref y) => foo(y),    B => bar(),    _ => frob(x),}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

match_result_ok📋
stylewarn

What it does

Checks for unnecessaryok() inwhile let.

Why is this bad?

Callingok() inwhile let is unnecessary, instead matchonOk(pat)

Example

while let Some(value) = iter.next().ok() {    vec.push(value)}if let Some(value) = iter.next().ok() {    vec.push(value)}

Use instead:

while let Ok(value) = iter.next() {    vec.push(value)}if let Ok(value) = iter.next() {       vec.push(value)}

Past names

  • if_let_some_result
Applicability:MachineApplicable(?)
Added in:1.57.0
Related Issues
View Source

match_same_arms📋
pedanticallow

What it does

Checks formatch with identical arm bodies.

Note: Does not lint on wildcards if thenon_exhaustive_omitted_patterns_lint feature isenabled and disallowed.

Why is this bad?

This is probably a copy & paste error. If arm bodiesare the same on purpose, you can factor themusing|.

Example

match foo {    Bar => bar(),    Quz => quz(),    Baz => bar(), // <= oops}

This should probably be

match foo {    Bar => bar(),    Quz => quz(),    Baz => baz(), // <= fixed}

or if the original code was not a typo:

match foo {    Bar | Baz => bar(), // <= shows the intent better    Quz => quz(),}
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

match_single_binding📋
complexitywarn

What it does

Checks for useless match that binds to only one value.

Why is this bad?

Readability and needless complexity.

Known problems

Suggested replacements may be incorrect whenmatchis actually binding temporary value, bringing a ‘dropped while borrowed’ error.

Example

match (a, b) {    (c, d) => {        // useless match    }}

Use instead:

let (c, d) = (a, b);
Applicability:MachineApplicable(?)
Added in:1.43.0
Related Issues
View Source

match_str_case_mismatch📋
correctnessdeny

What it does

Checks formatch expressions modifying the case of a string with non-compliant arms

Why is this bad?

The arm is unreachable, which is likely a mistake

Example

match &*text.to_ascii_lowercase() {    "foo" => {},    "Bar" => {},    _ => {},}

Use instead:

match &*text.to_ascii_lowercase() {    "foo" => {},    "bar" => {},    _ => {},}
Applicability:MachineApplicable(?)
Added in:1.58.0
Related Issues
View Source

match_wild_err_arm📋
pedanticallow

What it does

Checks for arm which matches all errors withErr(_)and take drastic actions likepanic!.

Why is this bad?

It is generally a bad practice, similar tocatching all exceptions in java withcatch(Exception)

Example

let x: Result<i32, &str> = Ok(3);match x {    Ok(_) => println!("ok"),    Err(_) => panic!("err"),}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

match_wildcard_for_single_variants📋
pedanticallow

What it does

Checks for wildcard enum matches for a single variant.

Why is this bad?

New enum variants added by library updates can be missed.

Known problems

Suggested replacements may not use correct path to enumif it’s not present in the current scope.

Example

match x {    Foo::A => {},    Foo::B => {},    _ => {},}

Use instead:

match x {    Foo::A => {},    Foo::B => {},    Foo::C => {},}
Applicability:MaybeIncorrect(?)
Added in:1.45.0
Related Issues
View Source

maybe_infinite_iter📋
pedanticallow

What it does

Checks for iteration that may be infinite.

Why is this bad?

While there may be places where this is acceptable(e.g., in event streams), in most cases this is simply an error.

Known problems

The code may have a condition to stop iteration, butthis lint is not clever enough to analyze it.

Example

let infinite_iter = 0..;[0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

mem_forget📋
restrictionallow

What it does

Checks for usage ofstd::mem::forget(t) wheret isDrop or has a field that implementsDrop.

Why restrict this?

std::mem::forget(t) preventst from running its destructor, possibly causing leaks.It is not possible to detect all means of creating leaks, but it may be desirable toprohibit the simple ones.

Example

mem::forget(Rc::new(55))
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

mem_replace_option_with_none📋
stylewarn

What it does

Checks formem::replace() on anOption withNone.

Why is this bad?

Option already has the methodtake() fortaking its current value (Some(..) or None) and replacing it withNone.

Example

use std::mem;let mut an_option = Some(0);let replaced = mem::replace(&mut an_option, None);

Is better expressed with:

let mut an_option = Some(0);let taken = an_option.take();
Applicability:MachineApplicable(?)
Added in:1.31.0
Related Issues
View Source

mem_replace_option_with_some📋
stylewarn

What it does

Checks formem::replace() on anOption withSome(…).

Why is this bad?

Option already has the methodreplace() fortaking its current value (Some(…) or None) and replacing it withSome(…).

Example

let mut an_option = Some(0);let replaced = std::mem::replace(&mut an_option, Some(1));

Is better expressed with:

let mut an_option = Some(0);let taken = an_option.replace(1);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.87.0
Related Issues
View Source

mem_replace_with_default📋
stylewarn

What it does

Checks forstd::mem::replace on a value of typeT withT::default().

Why is this bad?

std::mem module already has the methodtake totake the current value and replace it with the default value of that type.

Example

let mut text = String::from("foo");let replaced = std::mem::replace(&mut text, String::default());

Is better expressed with:

let mut text = String::from("foo");let taken = std::mem::take(&mut text);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.42.0
Related Issues
View Source

mem_replace_with_uninit📋
correctnessdeny

What it does

Checks formem::replace(&mut _, mem::uninitialized())andmem::replace(&mut _, mem::zeroed()).

Why is this bad?

This will lead to undefined behavior even if thevalue is overwritten later, because the uninitialized value may beobserved in the case of a panic.

Example

use std::mem;#[allow(deprecated, invalid_value)]fn myfunc (v: &mut Vec<i32>) {    let taken_v = unsafe { mem::replace(v, mem::uninitialized()) };    let new_v = may_panic(taken_v); // undefined behavior on panic    mem::forget(mem::replace(v, new_v));}

Thetake_mut crate offers a sound solution,at the cost of either lazily creating a replacement value or abortingon panic, to ensure that the uninitialized value cannot be observed.

Applicability:MachineApplicable(?)
Added in:1.39.0
Related Issues
View Source

min_ident_chars📋
restrictionallow

What it does

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 ittemporarily.

Why restrict this?

To improve readability by requiring that every variable has a name more specific than a single letter can be.

Example

for m in movies {    let title = m.t;}

Use instead:

for movie in movies {    let title = movie.title;}

Limitations

Trait implementations which use the same function or parameter name as the trait declaration willnot be warned about, even if the name is below the configured limit.

Configuration

  • allowed-idents-below-min-chars: Allowed names below the minimum allowed characters. The value".." can be used as part ofthe list to indicate, that the configured values should be appended to the defaultconfiguration of Clippy. By default, any configuration will replace the default value.

    (default:["i", "j", "x", "y", "z", "w", "n"])

  • min-ident-chars-threshold: Minimum chars an ident can have, anything below or equal to this will be linted.

    (default:1)

Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

min_max📋
correctnessdeny

What it does

Checks for expressions wherestd::cmp::min andmax areused to clamp values, but switched so that the result is constant.

Why is this bad?

This is in all probability not the intended outcome. Atthe least it hurts readability of the code.

Example

min(0, max(100, x))// orx.max(100).min(0)

It will always be equal to0. Probably the author meant to clamp the valuebetween 0 and 100, but has erroneously swappedmin andmax.

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

misaligned_transmute📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

Split intoclippy::cast_ptr_alignment andclippy::transmute_ptr_to_ptr.

Applicability:Unspecified(?)
Deprecated in:pre 1.29.0
Related Issues

mismatching_type_param_order📋
pedanticallow

What it does

Checks for type parameters which are positioned inconsistently betweena type definition and impl block. Specifically, a parameter in an implblock which has the same name as a parameter in the type def, but is ina different place.

Why is this bad?

Type parameters are determined by their position rather than name.Naming type parameters inconsistently may cause you to refer to thewrong type parameter.

Limitations

This lint only applies to impl blocks with simple generic params, e.g.A. If there is anything more complicated, such as a tuple, it will beignored.

Example

struct Foo<A, B> {    x: A,    y: B,}// inside the impl, B refers to Foo::Aimpl<B, A> Foo<B, A> {}

Use instead:

struct Foo<A, B> {    x: A,    y: B,}impl<A, B> Foo<A, B> {}
Applicability:Unspecified(?)
Added in:1.63.0
Related Issues
View Source

misnamed_getters📋
suspiciouswarn

What it does

Checks for getter methods that return a field that doesn’t correspondto the name of the method, when there is a field’s whose name matches that of the method.

Why is this bad?

It is most likely that such a method is a bug caused by a typo or by copy-pasting.

Example

struct A {    a: String,    b: String,}impl A {    fn a(&self) -> &str{        &self.b    }}

Use instead:

struct A {    a: String,    b: String,}impl A {    fn a(&self) -> &str{        &self.a    }}
Applicability:MaybeIncorrect(?)
Added in:1.67.0
Related Issues
View Source

misrefactored_assign_op📋
suspiciouswarn

What it does

Checks fora op= a op b ora op= b op a patterns.

Why is this bad?

Most likely these are bugs where one meant to writea op= b.

Known problems

Clippy cannot know for sure ifa op= a op b should havebeena = a op a op b ora = a op b/a op= b. Therefore, it suggests both.Ifa op= a op b is really the correct behavior it should bewritten asa = a op a op b as it’s less confusing.

Example

let mut a = 5;let b = 2;// ...a += a + b;
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

missing_assert_message📋
restrictionallow

What it does

Checks assertions without a custom panic message.

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 problematicand not what is failed because the assertion already conveys that.

Although the same reasoning applies to testing functions, this lint ignores them as they would be too noisy.Also, in most cases understanding the test failure would be easiercompared to understanding a complex invariant distributed around the codebase.

Known problems

This lint cannot check the quality of the custom panic messages.Hence, you can suppress this lint simply by adding placeholder messageslike “assertion failed”. However, we recommend coming up with good messagesthat provide useful information instead of placeholder messages thatdon’t provide any extra information.

Example

fn call(service: Service) {    assert!(service.ready);}

Use instead:

fn call(service: Service) {    assert!(service.ready, "`service.poll_ready()` must be called first to ensure that service is ready to receive requests");}
Applicability:Unspecified(?)
Added in:1.70.0
Related Issues
View Source

missing_asserts_for_indexing📋
restrictionallow

What it does

Checks for repeated slice indexing without asserting beforehand that the lengthis greater than the largest index used to index into the slice.

Why restrict this?

In the general case where the compiler does not have a lot of informationabout the length of a slice, indexing it repeatedly will generate a bounds checkfor every single index.

Asserting that the length of the slice is at least as large as the largest valueto index beforehand gives the compiler enough information to elide the bounds checks,effectively reducing the number of bounds checks from however many timesthe slice was indexed to just one (the assert).

Drawbacks

False positives. It is, in general, very difficult to predict how wellthe optimizer will be able to elide bounds checks and it very much depends onthe surrounding code. For example, indexing into the slice yielded by theslice::chunks_exactiterator will likely have all of the bounds checks elided even without an assertif thechunk_size is a constant.

Asserts are not tracked across function calls. Asserting the length of a slicein a different function likely gives the optimizer enough informationabout the length of a slice, but this lint will not detect that.

Example

fn sum(v: &[u8]) -> u8 {    // 4 bounds checks    v[0] + v[1] + v[2] + v[3]}

Use instead:

fn sum(v: &[u8]) -> u8 {    assert!(v.len() > 3);    // no bounds checks    v[0] + v[1] + v[2] + v[3]}
Applicability:MachineApplicable(?)
Added in:1.74.0
Related Issues
View Source

missing_const_for_fn📋
nurseryallow

What it does

Suggests the use ofconst in functions and methods where possible.

Why is this bad?

Not having the function const prevents callers of the function from being const as well.

Known problems

Const functions are currently still being worked on, with some features only being availableon nightly. This lint does not consider all edge cases currently and the suggestions may beincorrect if you are using this lint on stable.

Also, the lint only runs one pass over the code. Consider these two non-const functions:

fn a() -> i32 {    0}fn b() -> i32 {    a()}

When running Clippy, the lint will only suggest to makea const, becauseb at this timecan’t be const as it calls a non-const function. Makinga const and running Clippy again,will suggest to makeb const, too.

If you are marking a public function withconst, removing it again will break API compatibility.

Example

fn new() -> Self {    Self { random_number: 42 }}

Could be a const fn:

const fn new() -> Self {    Self { random_number: 42 }}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.34.0
Related Issues
View Source

missing_const_for_thread_local📋
perfwarn

What it does

Suggests to useconst inthread_local! macro if possible.

Why is this bad?

Thethread_local! macro wraps static declarations and makes them thread-local.It supports using aconst keyword that may be used for declarations that canbe evaluated as a constant expression. This can enable a more efficient threadlocal implementation that can avoid lazy initialization. For types that do notneed to be dropped, this can enable an even more efficient implementation thatdoes not need to track any additional state.

https://doc.rust-lang.org/std/macro.thread_local.html

Example

thread_local! {    static BUF: String = String::new();}

Use instead:

thread_local! {    static BUF: String = const { String::new() };}

Past names

  • thread_local_initializer_can_be_made_const
Applicability:MachineApplicable(?)
Added in:1.77.0
Related Issues
View Source

missing_docs_in_private_items📋
restrictionallow

What it does

Warns if there is missing documentation for any private documentable item.

Why restrict this?

Doc is good.rustc has aMISSING_DOCSallowed-by-default lint forpublic members, but has no way to enforce documentation of private items.This lint fixes that.

Configuration

  • missing-docs-allow-unused: Whether to allow fields starting with an underscore to skip documentation requirements

    (default:false)

  • missing-docs-in-crate-items: Whether toonly check for missing documentation in items visible within the currentcrate. For example,pub(crate) items.

    (default:false)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

missing_enforced_import_renames📋
stylewarn

What it does

Checks for imports that do not rename the item as specifiedin theenforced-import-renames config option.

Note: Even though this lint is warn-by-default, it will only trigger ifimport renames are defined in theclippy.toml file.

Why is this bad?

Consistency is important; if a project has defined import renames, then they should befollowed. More practically, some item names are too vague outside of their defining scope,in which case this can enforce a more meaningful naming.

Example

An example clippy.toml configuration:

enforced-import-renames = [    { path = "serde_json::Value", rename = "JsonValue" },]
use serde_json::Value;

Use instead:

use serde_json::Value as JsonValue;

Configuration

  • enforced-import-renames: The list of imports to always rename, a fully qualified path followed by the rename.

    (default:[])

Applicability:MachineApplicable(?)
Added in:1.55.0
Related Issues
View Source

missing_errors_doc📋
pedanticallow

What it does

Checks the doc comments of publicly visible functions thatreturn aResult type and warns if there is no# Errors section.

Why is this bad?

Documenting the type of errors that can be returned from afunction can help callers write code to handle the errors appropriately.

Examples

Since the following function returns aResult it has an# Errors section inits doc comment:

/// # Errors////// Will return `Err` if `filename` does not exist or the user does not have/// permission to read it.pub fn read(filename: String) -> io::Result<String> {    unimplemented!();}

Configuration

  • check-private-items: Whether to also run the listed lints on private items.

    (default:false)

Applicability:Unspecified(?)
Added in:1.41.0
Related Issues
View Source

missing_fields_in_debug📋
pedanticallow

What it does

Checks for manualcore::fmt::Debug implementations that do not use all fields.

Why is this bad?

A common mistake is to forget to update manualDebug implementations when adding a new fieldto a struct or a new variant to an enum.

At the same time, it also acts as a style lint to suggest usingcore::fmt::DebugStruct::finish_non_exhaustivefor the times when the user intentionally wants to leave out certain fields (e.g. to hide implementation details).

Known problems

This lint works based on theDebugStruct helper types provided by theFormatter,so this won’t detectDebug impls that use thewrite! macro.Oftentimes there is more logic to aDebug impl if it useswrite! macro, so it triesto be on the conservative side and not lint in those cases in an attempt to prevent false positives.

This lint also does not look through function calls, so calling a function does not consider fieldsused inside of that function as used by theDebug impl.

Lastly, it also ignores tuple structs as theirDebugTuple formatter does not have afinish_non_exhaustivemethod, as well as enums because their exhaustiveness is already checked by the compiler when matching on the enum,making it much less likely to accidentally forget to update theDebug impl when adding a new variant.

Example

use std::fmt;struct Foo {    data: String,    // implementation detail    hidden_data: i32}impl fmt::Debug for Foo {    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {        formatter            .debug_struct("Foo")            .field("data", &self.data)            .finish()    }}

Use instead:

use std::fmt;struct Foo {    data: String,    // implementation detail    hidden_data: i32}impl fmt::Debug for Foo {    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {        formatter            .debug_struct("Foo")            .field("data", &self.data)            .finish_non_exhaustive()    }}
Applicability:Unspecified(?)
Added in:1.70.0
Related Issues
View Source

missing_inline_in_public_items📋
restrictionallow

What it does

It lints if an exported function, method, trait method with default impl,or trait method impl is not#[inline].

Why restrict this?

When a function is not marked#[inline], it is nota “small” candidate for automatic inlining, and LTO is not in use, then it is notpossible for the function to be inlined into the code of any crate other than the one inwhich 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 ableto be inlined across crates even when LTO is disabled.This lint allows those crates to require all exported methods to be#[inline] by default, andthen opt out for specific methods where this might not make sense.

Example

pub fn foo() {} // missing #[inline]fn ok() {} // ok#[inline] pub fn bar() {} // ok#[inline(always)] pub fn baz() {} // okpub trait Bar {  fn bar(); // ok  fn def_bar() {} // missing #[inline]}struct Baz;impl Baz {    fn private() {} // ok}impl Bar for Baz {  fn bar() {} // ok - Baz is not exported}pub struct PubBaz;impl PubBaz {    fn private() {} // ok    pub fn not_private() {} // missing #[inline]}impl Bar for PubBaz {    fn bar() {} // missing #[inline]    fn def_bar() {} // missing #[inline]}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

missing_panics_doc📋
pedanticallow

What it does

Checks the doc comments of publicly visible functions thatmay panic and warns if there is no# Panics section.

Why is this bad?

Documenting the scenarios in which panicking occurscan help callers who do not want to panic to avoid those situations.

Examples

Since the following function may panic it has a# Panics section inits doc comment:

/// # Panics////// Will panic if y is 0pub fn divide_by(x: i32, y: i32) -> i32 {    if y == 0 {        panic!("Cannot divide by 0")    } else {        x / y    }}

Individual panics within a function can be ignored with#[expect] or#[allow]:

pub fn will_not_panic(x: usize) {    #[expect(clippy::missing_panics_doc, reason = "infallible")]    let y = NonZeroUsize::new(1).unwrap();    // If any panics are added in the future the lint will still catch them}

Configuration

  • check-private-items: Whether to also run the listed lints on private items.

    (default:false)

Applicability:Unspecified(?)
Added in:1.51.0
Related Issues
View Source

missing_safety_doc📋
stylewarn

What it does

Checks for the doc comments of publicly visibleunsafe functions and warns if there is no# Safety section.

Why is this bad?

Unsafe functions should document their safetypreconditions, so that users can be sure they are using them safely.

Examples

/// This function should really be documentedpub unsafe fn start_apocalypse(u: &mut Universe) {    unimplemented!();}

At least write a line about safety:

/// # Safety////// This function should not be called before the horsemen are ready.pub unsafe fn start_apocalypse(u: &mut Universe) {    unimplemented!();}

Configuration

  • check-private-items: Whether to also run the listed lints on private items.

    (default:false)

Applicability:Unspecified(?)
Added in:1.39.0
Related Issues
View Source

missing_spin_loop📋
perfwarn

What it does

Checks for empty spin loops

Why is this bad?

The loop body should have something likethread::park() or at leaststd::hint::spin_loop() to avoid needlessly burning cycles and conserveenergy. Perhaps even better use an actual lock, if possible.

Known problems

This lint doesn’t currently trigger onwhile let orloop { match .. { .. } } loops, which would be considered idiomatic incombination with e.g.AtomicBool::compare_exchange_weak.

Example

use core::sync::atomic::{AtomicBool, Ordering};let b = AtomicBool::new(true);// give a ref to `b` to another thread,wait for it to become falsewhile b.load(Ordering::Acquire) {};

Use instead:

while b.load(Ordering::Acquire) {    std::hint::spin_loop()}
Applicability:MachineApplicable(?)
Added in:1.61.0
Related Issues
View Source

missing_trait_methods📋
restrictionallow

What it does

Checks if a provided method is used implicitly by a traitimplementation.

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 ofthe inner type’s implementation.

This lint should typically be enabled on a specific traitimpl itemrather than globally.

Example

trait Trait {    fn required();    fn provided() {}}#[warn(clippy::missing_trait_methods)]impl Trait for Type {    fn required() { /* ... */ }}

Use instead:

trait Trait {    fn required();    fn provided() {}}#[warn(clippy::missing_trait_methods)]impl Trait for Type {    fn required() { /* ... */ }    fn provided() { /* ... */ }}
Applicability:Unspecified(?)
Added in:1.66.0
Related Issues
View Source

missing_transmute_annotations📋
suspiciouswarn

What it does

Checks if transmute calls have all generics specified.

Why is this bad?

If not, one or more unexpected types could be used duringtransmute(), potentially leadingto Undefined Behavior or other problems.

This is particularly dangerous in case a seemingly innocent/unrelated change causes typeinference to result in a different type. For example, iftransmute() is the tailexpression of anif-branch, and theelse-branch type changes, the compiler may silentlyinfer a different type to be returned bytransmute(). That is because the compiler isfree to change the inference of a type as long as that inference is technically correct,regardless of the programmer’s unknown expectation.

Both type-parameters, the input- and the output-type, to anytransmute() shouldbe given explicitly: Setting the input-type explicitly avoids confusion about what theargument’s type actually is. Setting the output-type explicitly avoids type-inferenceto infer a technically correct yet unexpected type.

Example

let mut x: i32 = 0;// Avoid "naked" calls to `transmute()`!x = std::mem::transmute([1u16, 2u16]);// `first_answers` is intended to transmute a slice of bool to a slice of u8.// But the programmer forgot to index the first element of the outer slice,// so we are actually transmuting from "pointers to slices" instead of// transmuting from "a slice of bool", causing a nonsensical result.let the_answers: &[&[bool]] = &[&[true, false, true]];let first_answers: &[u8] = std::mem::transmute(the_answers);

Use instead:

let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);// The explicit type parameters on `transmute()` makes the intention clear,// and cause a type-error if the actual types don't match our expectation.let the_answers: &[&[bool]] = &[&[true, false, true]];let first_answers: &[u8] = std::mem::transmute::<&[bool], &[u8]>(the_answers[0]);
Applicability:MaybeIncorrect(?)
Added in:1.79.0
Related Issues
View Source

mistyped_literal_suffixes📋
correctnessdeny

What it does

Warns for mistyped suffix in literals

Why is this bad?

This is most probably a typo

Known problems

  • Does not match on integers too large to fit in the corresponding unsigned type
  • Does not match on_127 since that is a valid grouping for decimal and octal numbers

Example

`2_32` => `2_i32``250_8 => `250_u8`
Applicability:MaybeIncorrect(?)
Added in:1.30.0
Related Issues
View Source

mixed_attributes_style📋
stylewarn

What it does

Checks for items that have the same kind of attributes with mixed styles (inner/outer).

Why is this bad?

Having both style of said attributes makes it more complicated to read code.

Known problems

This lint currently has false-negatives when mixing same attributesbut they have different path symbols, for example:

#[custom_attribute]pub fn foo() {    #![my_crate::custom_attribute]}

Example

#[cfg(linux)]pub fn foo() {    #![cfg(windows)]}

Use instead:

#[cfg(linux)]#[cfg(windows)]pub fn foo() {}
Applicability:Unspecified(?)
Added in:1.78.0
Related Issues
View Source

mixed_case_hex_literals📋
stylewarn

What it does

Warns on hexadecimal literals with mixed-case letterdigits.

Why is this bad?

It looks confusing.

Example

0x1a9BAcD

Use instead:

0x1A9BACD
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

mixed_read_write_in_expression📋
restrictionallow

What it does

Checks for a read and a write to the same variable wherewhether the read occurs before or after the write depends on the evaluationorder of sub-expressions.

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 orderaffects its behavior.

Known problems

Code which intentionally depends on the evaluationorder, or which is correct for any evaluation order.

Example

let mut x = 0;let a = {    x = 1;    1} + x;// Unclear whether a is 1 or 2.

Use instead:

let tmp = {    x = 1;    1};let a = tmp + x;

Past names

  • eval_order_dependence
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

mod_module_files📋
restrictionallow

What it does

Checks that module layout uses only self named module files; bansmod.rs files.

Why restrict this?

Having multiple module layout styles in a project can be confusing.

Example

src/  stuff/    stuff_files.rs    mod.rs  lib.rs

Use instead:

src/  stuff/    stuff_files.rs  stuff.rs  lib.rs
Applicability:Unspecified(?)
Added in:1.57.0
Related Issues
View Source

module_inception📋
stylewarn

What it does

Checks for modules that have the same name as theirparent module

Why is this bad?

A typical beginner mistake is to havemod foo; andagainmod foo { .. } infoo.rs.The expectation is that items inside the innermod foo { .. } are thenavailablethroughfoo::x, but they are only available throughfoo::foo::x.If this is done on purpose, it would be better to choose a morerepresentative module name.

Example

// lib.rsmod foo;// foo.rsmod foo {    ...}

Configuration

  • allow-private-module-inception: Whether to allow module inception if it’s not public.

    (default:false)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

module_name_repetitions📋
restrictionallow

What it does

Detects public item names that are prefixed or suffixed by thecontaining public module’s name.

Why is this bad?

It requires the user to type the module name twice in each usage,especially if they choose to import the module rather than its contents.

Lack of such repetition is also the style used in the Rust standard library;e.g.io::Error andfmt::Error rather thanio::IoError andfmt::FmtError;andarray::from_ref rather thanarray::array_from_ref.

Known issues

Glob re-exports are ignored; e.g. this will not warn even though it should:

pub mod foo {    mod iteration {        pub struct FooIter {}    }    pub use iteration::*; // creates the path `foo::FooIter`}

Example

mod cake {    struct BlackForestCake;}

Use instead:

mod cake {    struct BlackForest;}

Past names

  • stutter

Configuration

  • allow-exact-repetitions: Whether an item should be allowed to have the same name as its containing module

    (default:true)

  • allowed-prefixes: List of prefixes to allow when determining whether an item’s name ends with the module’s name.If the rest of an item’s name is an allowed prefix (e.g. itemToFoo orto_foo in modulefoo),then don’t emit a warning.

Example

allowed-prefixes = [ "to", "from" ]

Noteworthy

  • By default, the following prefixes are allowed:to,as,into,from,try_into andtry_from

  • PascalCase variant is included automatically for each snake_case variant (e.g. iftry_into is included,TryInto will also be included)

  • Use".." as part of the list to indicate that the configured values should be appended to thedefault configuration of Clippy. By default, any configuration will replace the default value

    (default:["to", "as", "into", "from", "try_into", "try_from"])

Applicability:Unspecified(?)
Added in:1.33.0
Related Issues
View Source

modulo_arithmetic📋
restrictionallow

What it does

Checks for modulo arithmetic.

Why restrict this?

The results of modulo (%) operation might differdepending on the language, when negative numbers are involved.If you interop with different languages it might be beneficialto double check all places that use modulo arithmetic.

For example, in Rust17 % -3 = 2, but in Python17 % -3 = -1.

Example

let x = -17 % 3;

Configuration

  • allow-comparison-to-zero: Don’t lint when comparing the result of a modulo operation to zero.

    (default:true)

Applicability:Unspecified(?)
Added in:1.42.0
Related Issues
View Source

modulo_one📋
correctnessdeny

What it does

Checks for getting the remainder of integer division by one or minusone.

Why is this bad?

The result for a divisor of one can only ever be zero; forminus one it can cause panic/overflow (if the left operand is the minimal value ofthe respective integer type) or results in zero. No one will write such codedeliberately, unless trying to win an Underhanded Rust Contest. Even for thatcontest, it’s probably a bad idea. Use something more underhanded.

Example

let a = x % 1;let a = x % -1;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

multi_assignments📋
suspiciouswarn

What it does

Checks for nested assignments.

Why is this bad?

While this is in most cases already a type mismatch,the result of an assignment being() can throw off people coming from languages like python or C,where such assignments return a copy of the assigned value.

Example

a = b = 42;

Use instead:

b = 42;a = b;
Applicability:Unspecified(?)
Added in:1.65.0
Related Issues
View Source

multiple_bound_locations📋
suspiciouswarn

What it does

Check if a generic is defined both in the bound predicate and in thewhere clause.

Why is this bad?

It can be confusing for developers when seeing bounds for a generic in multiple places.

Example

fn ty<F: std::fmt::Debug>(a: F)where    F: Sized,{}

Use instead:

fn ty<F>(a: F)where    F: Sized + std::fmt::Debug,{}
Applicability:Unspecified(?)
Added in:1.78.0
Related Issues
View Source

multiple_crate_versions📋
cargoallow

What it does

Checks to see if multiple versions of a crate are beingused.

Why is this bad?

This bloats the size of targets, and can lead toconfusing error messages when structs or traits are used interchangeablybetween different versions of a crate.

Known problems

Because this can be caused purely by the dependenciesthemselves, it’s not always possible to fix this issue.In those cases, you can allow that specific crate usingtheallowed_duplicate_crates configuration option.

Example

[dependencies]ctrlc = "=3.1.0"ansi_term = "=0.11.0"

Configuration

  • allowed-duplicate-crates: A list of crate names to allow duplicates of

    (default:[])

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

multiple_inherent_impl📋
restrictionallow

What it does

Checks for multiple inherent implementations of a struct

The config option controls the scope in which multiple inherentimpl blocks for the samestruct are linted, allowing values ofmodule (only within the same module),file(within the same file), orcrate (anywhere in the crate, default).

Why restrict this?

Splitting the implementation of a type makes the code harder to navigate.

Example

struct X;impl X {    fn one() {}}impl X {    fn other() {}}

Could be written:

struct X;impl X {    fn one() {}    fn other() {}}

Configuration

  • inherent-impl-lint-scope: Sets the scope (“crate”, “file”, or “module”) in which duplicate inherentimpl blocks for the same type are linted.

    (default:"crate")

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

multiple_unsafe_ops_per_block📋
restrictionallow

What it does

Checks forunsafe blocks that contain more than one unsafe operation.

Why restrict this?

Combined withundocumented_unsafe_blocks,this lint ensures that each unsafe operation must be independently justified.Combined withunused_unsafe, this lint also ensureselimination of unnecessary unsafe blocks through refactoring.

Example

/// Reads a `char` from the given pointer.////// # Safety////// `ptr` must point to four consecutive, initialized bytes which/// form a valid `char` when interpreted in the native byte order.fn read_char(ptr: *const u8) -> char {    // SAFETY: The caller has guaranteed that the value pointed    // to by `bytes` is a valid `char`.    unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }}

Use instead:

/// Reads a `char` from the given pointer.////// # Safety////// - `ptr` must be 4-byte aligned, point to four consecutive///   initialized bytes, and be valid for reads of 4 bytes./// - The bytes pointed to by `ptr` must represent a valid///   `char` when interpreted in the native byte order.fn read_char(ptr: *const u8) -> char {    // SAFETY: `ptr` is 4-byte aligned, points to four consecutive    // initialized bytes, and is valid for reads of 4 bytes.    let int_value = unsafe { *ptr.cast::<u32>() };    // SAFETY: The caller has guaranteed that the four bytes    // pointed to by `bytes` represent a valid `char`.    unsafe { char::from_u32_unchecked(int_value) }}
Applicability:Unspecified(?)
Added in:1.69.0
Related Issues
View Source

must_use_candidate📋
pedanticallow

What it does

Checks for public functions that have no#[must_use] attribute, but return something not already markedmust-use, have no mutable arg and mutate no statics.

Why is this bad?

Not bad at all, this lint just shows places whereyou could add the attribute.

Known problems

The lint only checks the arguments for mutabletypes without looking if they are actually changed. On the other hand,it also ignores a broad range of potentially interesting side effects,because we cannot decide whether the programmer intends the function tobe called for the side effect or the result. Expect many falsepositives. At least we don’t lint if the result type is unit or already#[must_use].

Examples

// this could be annotated with `#[must_use]`.pub fn id<T>(t: T) -> T { t }
Applicability:MachineApplicable(?)
Added in:1.40.0
Related Issues
View Source

must_use_unit📋
stylewarn

What it does

Checks for a#[must_use] attribute onunit-returning functions and methods.

Why is this bad?

Unit values are useless. The attribute is likelya remnant of a refactoring that removed the return type.

Examples

#[must_use]fn useless() { }
Applicability:MachineApplicable(?)
Added in:1.40.0
Related Issues
View Source

mut_from_ref📋
correctnessdeny

What it does

This lint checks for functions that take immutable references and returnmutable ones. This will not trigger if no unsafe code exists as thereare multiple safe functions which will do this transformation

To be on the conservative side, if there’s at least one mutablereference with the output lifetime, this lint will not trigger.

Why is this bad?

Creating a mutable reference which can be repeatably derived from animmutable reference is unsound as it allows creating multiple livemutable references to the same object.

Thiserror actuallylead to an interim Rust release 1.15.1.

Known problems

This pattern is used by memory allocators to allow allocating multipleobjects while returning mutable references to each one. So long asdifferent mutable references are returned each time such a function maybe safe.

Example

fn foo(&Foo) -> &mut Bar { .. }
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

mut_mut📋
pedanticallow

What it does

Checks for instances ofmut mut references.

Why is this bad?

This is usually just a typo or a misunderstanding of how references work.

Example

let x = &mut &mut 1;let mut x = &mut 1;let y = &mut x;fn foo(x: &mut &mut u32) {}

Use instead

let x = &mut 1;let mut x = &mut 1;let y = &mut *x; // reborrowfn foo(x: &mut u32) {}
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

mut_mutex_lock📋
stylewarn

What it does

Checks for&mut Mutex::lock calls

Why is this bad?

Mutex::lock is less efficient thancallingMutex::get_mut. In addition you also have a staticallyguarantee that the mutex isn’t locked, instead of just a runtimeguarantee.

Example

use std::sync::{Arc, Mutex};let mut value_rc = Arc::new(Mutex::new(42_u8));let value_mutex = Arc::get_mut(&mut value_rc).unwrap();let mut value = value_mutex.lock().unwrap();*value += 1;

Use instead:

use std::sync::{Arc, Mutex};let mut value_rc = Arc::new(Mutex::new(42_u8));let value_mutex = Arc::get_mut(&mut value_rc).unwrap();let value = value_mutex.get_mut().unwrap();*value += 1;
Applicability:MaybeIncorrect(?)
Added in:1.49.0
Related Issues
View Source

mut_range_bound📋
suspiciouswarn

What it does

Checks for loops with a range bound that is a mutable variable.

Why is this bad?

One might think that modifying the mutable variable changes the loop bounds. It doesn’t.

Known problems

False positive when mutation is followed by abreak, but thebreak is not immediatelyafter the mutation:

let mut x = 5;for _ in 0..x {    x += 1; // x is a range bound that is mutated    ..; // some other expression    break; // leaves the loop, so mutation is not an issue}

False positive on nested loops (#6072)

Example

let mut foo = 42;for i in 0..foo {    foo -= 1;    println!("{i}"); // prints numbers from 0 to 41, not 0 to 21}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

mutable_key_type📋
suspiciouswarn

What it does

Checks for sets/maps with mutable key types.

Why is this bad?

All ofHashMap,HashSet,BTreeMap andBtreeSet rely on either the hash or the order of keys be unchanging,so having types with interior mutability is a bad idea.

Known problems

False Positives

It’s correct to use a struct that contains interior mutability as a key when itsimplementation ofHash orOrd doesn’t access any of the interior mutable types.However, this lint is unable to recognize this, so it will often cause false positives inthese cases.

False Negatives

This lint does not follow raw pointers (*const T or*mut T) asHash andOrdapply only to theaddress of the contained value. This can cause false negatives forcustom collections that use raw pointers internally.

Example

use std::cmp::{PartialEq, Eq};use std::collections::HashSet;use std::hash::{Hash, Hasher};use std::sync::atomic::AtomicUsize;struct Bad(AtomicUsize);impl PartialEq for Bad {    fn eq(&self, rhs: &Self) -> bool {         ..    }}impl Eq for Bad {}impl Hash for Bad {    fn hash<H: Hasher>(&self, h: &mut H) {        ..    }}fn main() {    let _: HashSet<Bad> = HashSet::new();}

Configuration

  • ignore-interior-mutability: A list of paths to types that should be treated as if they do not contain interior mutability

    (default:["bytes::Bytes"])

Applicability:Unspecified(?)
Added in:1.42.0
Related Issues
View Source

mutex_atomic📋
restrictionallow

What it does

Checks for usage ofMutex<X> where an atomic will do.

Why restrict this?

Using a mutex just to make access to a plain bool orreference sequential is shooting flies with cannons.std::sync::atomic::AtomicBool andstd::sync::atomic::AtomicPtr are leaner andfaster.

On the other hand,Mutexes are, in general, easier toverify correctness. An atomic does not behave the same asan equivalent mutex. Seethis issue’scommentary for more details.

Known problems

  • This lint cannot detect if the mutex is actually usedfor waiting before a critical section.
  • This lint has a false positive that warns without considering the casewhereMutex is used together withCondvar.

Example

let x = Mutex::new(&y);

Use instead:

let x = AtomicBool::new(y);
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

mutex_integer📋
restrictionallow

What it does

Checks for usage ofMutex<X> whereX is an integraltype.

Why restrict this?

Using a mutex just to make access to a plain integersequential isshooting flies with cannons.std::sync::atomic::AtomicUsize is leaner and faster.

On the other hand,Mutexes are, in general, easier toverify correctness. An atomic does not behave the same asan equivalent mutex. Seethis issue’scommentary for more details.

Known problems

  • This lint cannot detect if the mutex is actually usedfor waiting before a critical section.
  • This lint has a false positive that warns without considering the casewhereMutex is used together withCondvar.
  • This lint suggest usingAtomicU64 instead ofMutex<u64>, butAtomicU64 is not available on some 32-bit platforms.

Example

let x = Mutex::new(0usize);

Use instead:

let x = AtomicUsize::new(0usize);
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

naive_bytecount📋
pedanticallow

What it does

Checks for naive byte counts

Why is this bad?

Thebytecountcrate has methods to count your bytes faster, especially for large slices.

Known problems

If you have predominantly small slices, thebytecount::count(..) method may actually be slower. However, if you canensure that less than 2³²-1 matches arise, thenaive_count_32(..) can befaster in those cases.

Example

let count = vec.iter().filter(|x| **x == 0u8).count();

Use instead:

let count = bytecount::count(&vec, 0u8);
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_arbitrary_self_type📋
complexitywarn

What it does

The lint checks forself in fn parameters thatspecify theSelf-type explicitly

Why is this bad?

Increases the amount and decreases the readability of code

Example

enum ValType {    I32,    I64,    F32,    F64,}impl ValType {    pub fn bytes(self: Self) -> usize {        match self {            Self::I32 | Self::F32 => 4,            Self::I64 | Self::F64 => 8,        }    }}

Could be rewritten as

enum ValType {    I32,    I64,    F32,    F64,}impl ValType {    pub fn bytes(self) -> usize {        match self {            Self::I32 | Self::F32 => 4,            Self::I64 | Self::F64 => 8,        }    }}
Applicability:MachineApplicable(?)
Added in:1.47.0
Related Issues
View Source

needless_as_bytes📋
complexitywarn

What it does

It detects useless calls tostr::as_bytes() before callinglen() oris_empty().

Why is this bad?

Thelen() andis_empty() methods are also directly available on strings, and theyreturn identical results. In particular,len() on a string returns the number ofbytes.

Example

let len = "some string".as_bytes().len();let b = "some string".as_bytes().is_empty();

Use instead:

let len = "some string".len();let b = "some string".is_empty();
Applicability:MachineApplicable(?)
Added in:1.84.0
Related Issues
View Source

needless_bitwise_bool📋
pedanticallow

What it does

Checks for usage of bitwise and/or operators between booleans, where performance may be improved by usinga lazy and.

Why is this bad?

The bitwise operators do not support short-circuiting, so it may hinder code performance.Additionally, boolean logic “masked” as bitwise logic is not caught by lints likeunnecessary_fold

Known problems

This lint evaluates only when the right side is determined to have no side effects. At this time, thatdetermination is quite conservative.

Example

let (x,y) = (true, false);if x & !y {} // where both x and y are booleans

Use instead:

let (x,y) = (true, false);if x && !y {}
Applicability:MachineApplicable(?)
Added in:1.54.0
Related Issues
View Source

needless_bool📋
complexitywarn

What it does

Checks for expressions of the formif c { true } else { false } (or vice versa) and suggests using the condition directly.

Why is this bad?

Redundant code.

Known problems

Maybe false positives: Sometimes, the two branches arepainstakingly documented (which we, of course, do not detect), so theymayhave some value. Even then, the documentation can be rewritten to match theshorter code.

Example

if x {    false} else {    true}

Use instead:

!x
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_bool_assign📋
complexitywarn

What it does

Checks for expressions of the formif c { x = true } else { x = false }(or vice versa) and suggest assigning the variable directly from thecondition.

Why is this bad?

Redundant code.

Example

if must_keep(x, y) {    skip = false;} else {    skip = true;}

Use instead:

skip = !must_keep(x, y);
Applicability:MachineApplicable(?)
Added in:1.71.0
Related Issues
View Source

needless_borrow📋
stylewarn

What it does

Checks for address of operations (&) that are going tobe dereferenced immediately by the compiler.

Why is this bad?

Suggests that the receiver of the expression borrowsthe expression.

Known problems

The lint cannot tell when the implementation of a traitfor&T andT do different things. Removing a borrowin such a case can change the semantics of the code.

Example

fn fun(_a: &i32) {}let x: &i32 = &&&&&&5;fun(&x);

Use instead:

let x: &i32 = &5;fun(x);

Past names

  • ref_in_deref

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_borrowed_reference📋
complexitywarn

What it does

Checks for bindings that needlessly destructure a reference and borrow the innervalue with&ref.

Why is this bad?

This pattern has no effect in almost all cases.

Example

let mut v = Vec::<String>::new();v.iter_mut().filter(|&ref a| a.is_empty());if let &[ref first, ref second] = v.as_slice() {}

Use instead:

let mut v = Vec::<String>::new();v.iter_mut().filter(|a| a.is_empty());if let [first, second] = v.as_slice() {}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_borrows_for_generic_args📋
stylewarn

What it does

Checks for borrow operations (&) that are used as a generic argument to afunction when the borrowed value could be used.

Why is this bad?

Suggests that the receiver of the expression borrowsthe expression.

Known problems

The lint cannot tell when the implementation of a traitfor&T andT do different things. Removing a borrowin such a case can change the semantics of the code.

Example

fn f(_: impl AsRef<str>) {}let x = "foo";f(&x);

Use instead:

fn f(_: impl AsRef<str>) {}let x = "foo";f(x);
Applicability:MachineApplicable(?)
Added in:1.74.0
Related Issues
View Source

needless_character_iteration📋
suspiciouswarn

What it does

Checks if an iterator is used to check if a string is ascii.

Why is this bad?

Thestr type already implements theis_ascii method.

Example

"foo".chars().all(|c| c.is_ascii());

Use instead:

"foo".is_ascii();
Applicability:MachineApplicable(?)
Added in:1.81.0
Related Issues
View Source

needless_collect📋
nurseryallow

What it does

Checks for functions collecting an iterator when collectis not needed.

Why is this bad?

collect causes the allocation of a new data structure,when this allocation may not be needed.

Example

let len = iterator.collect::<Vec<_>>().len();

Use instead:

let len = iterator.count();
Applicability:MachineApplicable(?)
Added in:1.30.0
Related Issues
View Source

needless_continue📋
pedanticallow

What it does

The lint checks forif-statements appearing in loopsthat contain acontinue statement in either their main blocks or theirelse-blocks, when omitting theelse-block possibly with somerearrangement of code can make the code easier to understand.The lint also checks if the last statement in the loop is acontinue

Why is this bad?

Having explicitelse blocks forif statementscontainingcontinue in their THEN branch adds unnecessary branching andnesting to the code. Having an else block containing justcontinue canalso be better written by grouping the statements following the wholeifstatement within the THEN block and omitting the else block completely.

Example

while condition() {    update_condition();    if x {        // ...    } else {        continue;    }    println!("Hello, world");}

Could be rewritten as

while condition() {    update_condition();    if x {        // ...        println!("Hello, world");    }}

As another example, the following code

loop {    if waiting() {        continue;    } else {        // Do something useful    }    # break;}

Could be rewritten as

loop {    if waiting() {        continue;    }    // Do something useful    # break;}
fn foo() -> ErrorKind { ErrorKind::NotFound }for _ in 0..10 {    match foo() {        ErrorKind::NotFound => {            eprintln!("not found");            continue        }        ErrorKind::TimedOut => {            eprintln!("timeout");            continue        }        _ => {            eprintln!("other error");            continue        }    }}

Could be rewritten as

fn foo() -> ErrorKind { ErrorKind::NotFound }for _ in 0..10 {    match foo() {        ErrorKind::NotFound => {            eprintln!("not found");        }        ErrorKind::TimedOut => {            eprintln!("timeout");        }        _ => {            eprintln!("other error");        }    }}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_doctest_main📋
stylewarn

What it does

Checks forfn main() { .. } in doctests

Why is this bad?

The test can be shorter (and likely more readable)if thefn main() is left implicit.

Examples

/// An example of a doctest with a `main()` function////// # Examples////// ```/// fn main() {///     // this needs not be in an `fn`/// }/// ```fn needless_main() {    unimplemented!();}
Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

needless_else📋
stylewarn

What it does

Checks for emptyelse branches.

Why is this bad?

An empty else branch does nothing and can be removed.

Example

if check() {    println!("Check successful!");} else {}

Use instead:

if check() {    println!("Check successful!");}
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

needless_for_each📋
pedanticallow

What it does

Checks for usage offor_each that would be more simply written as afor loop.

Why is this bad?

for_each may be used after applying iterator transformers likefilter for better readability and performance. It may also be used to fit a simpleoperation on one line.But when none of these apply, a simplefor loop is more idiomatic.

Example

let v = vec![0, 1, 2];v.iter().for_each(|elem| {    println!("{elem}");})

Use instead:

let v = vec![0, 1, 2];for elem in &v {    println!("{elem}");}

Known Problems

When doing things such as:

let v = vec![0, 1, 2];v.iter().for_each(|elem| unsafe {    libc::printf(c"%d\n".as_ptr(), elem);});

This lint will not trigger.

Applicability:MachineApplicable(?)
Added in:1.53.0
Related Issues
View Source

needless_ifs📋
complexitywarn

What it does

Checks for emptyif branches with no else branch.

Why is this bad?

It can be entirely omitted, and often the condition too.

Known issues

This will usually only suggest to remove theif statement, not the condition. Other lintssuch asno_effect will take care of removing the condition if it’s unnecessary.

Example

if really_expensive_condition(&i) {}if really_expensive_condition_with_side_effects(&mut i) {}

Use instead:

// <omitted>really_expensive_condition_with_side_effects(&mut i);

Past names

  • needless_if
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

needless_late_init📋
stylewarn

What it does

Checks for late initializations that can be replaced by alet statementwith an initializer.

Why is this bad?

Assigning in thelet statement is less repetitive.

Example

let a;a = 1;let b;match 3 {    0 => b = "zero",    1 => b = "one",    _ => b = "many",}let c;if true {    c = 1;} else {    c = -1;}

Use instead:

let a = 1;let b = match 3 {    0 => "zero",    1 => "one",    _ => "many",};let c = if true {    1} else {    -1};
Applicability:MachineApplicable(?)
Added in:1.59.0
Related Issues
View Source

needless_lifetimes📋
complexitywarn

What it does

Checks for lifetime annotations which can be removed byrelying on lifetime elision.

Why is this bad?

The additional lifetimes make the code look morecomplicated, while there is nothing out of the ordinary going on. Removingthem leads to more readable code.

Known problems

This lint ignores functions withwhere clauses that referencelifetimes to prevent false positives.

Example

// Unnecessary lifetime annotationsfn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {    x}

Use instead:

fn elided(x: &u8, y: u8) -> &u8 {    x}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_match📋
complexitywarn

What it does

Checks for unnecessarymatch or match-likeif let returns forOption andResultwhen function signatures are the same.

Why is this bad?

Thismatch block does nothing and might not be what the coder intended.

Example

fn foo() -> Result<(), i32> {    match result {        Ok(val) => Ok(val),        Err(err) => Err(err),    }}fn bar() -> Option<i32> {    if let Some(val) = option {        Some(val)    } else {        None    }}

Could be replaced as

fn foo() -> Result<(), i32> {    result}fn bar() -> Option<i32> {    option}
Applicability:MachineApplicable(?)
Added in:1.61.0
Related Issues
View Source

needless_maybe_sized📋
suspiciouswarn

What it does

Lints?Sized bounds applied to type parameters that cannot be unsized

Why is this bad?

The?Sized bound is misleading because it cannot be satisfied by anunsized type

Example

// `T` cannot be unsized because `Clone` requires it to be `Sized`fn f<T: Clone + ?Sized>(t: &T) {}

Use instead:

fn f<T: Clone>(t: &T) {}// or choose alternative bounds for `T` so that it can be unsized
Applicability:MaybeIncorrect(?)
Added in:1.81.0
Related Issues
View Source

needless_option_as_deref📋
complexitywarn

What it does

Checks for no-op uses ofOption::{as_deref, as_deref_mut},for example,Option<&T>::as_deref() returns the same type.

Why is this bad?

Redundant code and improving readability.

Example

let a = Some(&1);let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>

Use instead:

let a = Some(&1);let b = a;
Applicability:MachineApplicable(?)
Added in:1.57.0
Related Issues
View Source

needless_option_take📋
complexitywarn

What it does

Checks for callingtake function afteras_ref.

Why is this bad?

Redundant code.take writesNone to its argument.In this case the modification is useless as it’s a temporary that cannot be read from afterwards.

Example

let x = Some(3);x.as_ref().take();

Use instead:

let x = Some(3);x.as_ref();
Applicability:MachineApplicable(?)
Added in:1.62.0
Related Issues
View Source

needless_parens_on_range_literals📋
stylewarn

What it does

The lint checks for parenthesis on literals in range statements that aresuperfluous.

Why is this bad?

Having superfluous parenthesis makes the code less readableoverhead when reading.

Example

for i in (0)..10 {  println!("{i}");}

Use instead:

for i in 0..10 {  println!("{i}");}
Applicability:MachineApplicable(?)
Added in:1.63.0
Related Issues
View Source

needless_pass_by_ref_mut📋
nurseryallow

What it does

Check if a&mut function argument is actually used mutably.

Be careful if the function is publicly reexported as it would break compatibility withusers of this function, when the users pass this function as an argument.

Why is this bad?

Lessmut means less fights with the borrow checker. It can also lead to moreopportunities for parallelization.

Example

fn foo(y: &mut i32) -> i32 {    12 + *y}

Use instead:

fn foo(y: &i32) -> i32 {    12 + *y}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:1.73.0
Related Issues
View Source

needless_pass_by_value📋
pedanticallow

What it does

Checks for functions taking arguments by value, but notconsuming them in itsbody.

Why is this bad?

Taking arguments by reference is more flexible and cansometimes avoidunnecessary allocations.

Known problems

  • This lint suggests taking an argument by reference,however sometimes it is better to let users decide the argument type(by usingBorrow trait, for example), depending on how the function is used.

Example

fn foo(v: Vec<i32>) {    assert_eq!(v.len(), 42);}

should be

fn foo(v: &[i32]) {    assert_eq!(v.len(), 42);}
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_pub_self📋
stylewarn

What it does

Checks for usage ofpub(self) andpub(in self).

Why is this bad?

It’s unnecessary, omitting thepub entirely will give the same results.

Example

pub(self) type OptBox<T> = Option<Box<T>>;

Use instead:

type OptBox<T> = Option<Box<T>>;
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

needless_question_mark📋
complexitywarn

What it does

Suggests replacingOk(x?) orSome(x?) withx in return positions where the? operatoris not needed to convert the type ofx.

Why is this bad?

There’s no reason to use? to short-circuit when execution of the body will end there anyway.

Example

fn f(s: &str) -> Option<usize> {    Some(s.find('x')?)}fn g(s: &str) -> Result<usize, ParseIntError> {    Ok(s.parse()?)}

Use instead:

fn f(s: &str) -> Option<usize> {    s.find('x')}fn g(s: &str) -> Result<usize, ParseIntError> {    s.parse()}
Applicability:MachineApplicable(?)
Added in:1.51.0
Related Issues
View Source

needless_range_loop📋
stylewarn

What it does

Checks for looping over the range of0..len of somecollection just to get the values by index.

Why is this bad?

Just iterating the collection itself makes the intentmore clear and is probably faster because it eliminatesthe bounds check that is done when indexing.

Example

let vec = vec!['a', 'b', 'c'];for i in 0..vec.len() {    println!("{}", vec[i]);}

Use instead:

let vec = vec!['a', 'b', 'c'];for i in vec {    println!("{}", i);}
Applicability:HasPlaceholders(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_raw_string_hashes📋
pedanticallow

What it does

Checks for raw string literals with an unnecessary amount of hashes around them.

Why is this bad?

It’s just unnecessary, and makes it look like there’s more escaping needed than is actuallynecessary.

Example

let r = r###"Hello, "world"!"###;

Use instead:

let r = r#"Hello, "world"!"#;

Configuration

  • allow-one-hash-in-raw-strings: Whether to allowr#""# whenr"" can be used

    (default:false)

Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

needless_raw_strings📋
restrictionallow

What it does

Checks for raw string literals where a string literal can be used instead.

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 moreidiomatic than a string literal, so it’s opt-in.

Example

let r = r"Hello, world!";

Use instead:

let r = "Hello, world!";
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

needless_return📋
stylewarn

What it does

Checks for return statements at the end of a block.

Why is this bad?

Removing thereturn and semicolon will make the codemore rusty.

Example

fn foo(x: usize) -> usize {    return x;}

simplify to

fn foo(x: usize) -> usize {    x}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

needless_return_with_question_mark📋
stylewarn

What it does

Checks for return statements onErr paired with the? operator.

Why is this bad?

Thereturn is unnecessary.

Returns may be used to add attributes to the return expression. Returnstatements with attributes are therefore be accepted by this lint.

Example

fn foo(x: usize) -> Result<(), Box<dyn Error>> {    if x == 0 {        return Err(...)?;    }    Ok(())}

simplify to

fn foo(x: usize) -> Result<(), Box<dyn Error>> {    if x == 0 {        Err(...)?;    }    Ok(())}

if paired withtry_err, use instead:

fn foo(x: usize) -> Result<(), Box<dyn Error>> {    if x == 0 {        return Err(...);    }    Ok(())}
Applicability:MachineApplicable(?)
Added in:1.73.0
Related Issues
View Source

needless_splitn📋
complexitywarn

What it does

Checks for usage ofstr::splitn (orstr::rsplitn) where usingstr::split would be the same.

Why is this bad?

The functionsplit is simpler and there is no performance difference in these cases, consideringthat both functions return a lazy iterator.

Example

let str = "key=value=add";let _ = str.splitn(3, '=').next().unwrap();

Use instead:

let str = "key=value=add";let _ = str.split('=').next().unwrap();
Applicability:MachineApplicable(?)
Added in:1.59.0
Related Issues
View Source

needless_update📋
complexitywarn

What it does

Checks for needlessly including a base struct on updatewhen all fields are changed anyway.

This lint is not applied to structs marked withnon_exhaustive.

Why is this bad?

This will cost resources (because the base has to besomewhere), and make the code less readable.

Example

Point {    x: 1,    y: 1,    z: 1,    ..zero_point};

Use instead:

// Missing field `z`Point {    x: 1,    y: 1,    ..zero_point};
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

neg_cmp_op_on_partial_ord📋
complexitywarn

What it does

Checks for the usage of negated comparison operators on types which only implementPartialOrd (e.g.,f64).

Why is this bad?

These operators make it easy to forget that the underlying types actually allow not only threepotential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This isespecially easy to miss if the operator based comparison result is negated.

Example

let a = 1.0;let b = f64::NAN;let not_less_or_equal = !(a <= b);

Use instead:

use std::cmp::Ordering;let _not_less_or_equal = match a.partial_cmp(&b) {    None | Some(Ordering::Greater) => true,    _ => false,};
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

neg_multiply📋
stylewarn

What it does

Checks for multiplication by -1 as a form of negation.

Why is this bad?

It’s more readable to just negate.

Example

let a = x * -1;

Use instead:

let a = -x;
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

negative_feature_names📋
cargoallow

What it does

Checks for negative feature names with prefixno- ornot-

Why is this bad?

Features are supposed to be additive, and negatively-named features violate it.

Example

[features]default = []no-abc = []not-def = []

Use instead:

[features]default = ["abc", "def"]abc = []def = []
Applicability:Unspecified(?)
Added in:1.57.0
Related Issues
View Source

never_loop📋
correctnessdeny

What it does

Checks for loops that will alwaysbreak,return orcontinue an outer loop.

Why is this bad?

This loop never loops, all it does is obfuscating thecode.

Example

loop {    ..;    break;}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

new_ret_no_self📋
stylewarn

What it does

Checks fornew not returning a type that containsSelf.

Why is this bad?

As a convention,new methods are used to make a newinstance of a type.

Example

In an impl block:

impl Foo {    fn new() -> NotAFoo {    }}
struct Bar(Foo);impl Foo {    // Bad. The type name must contain `Self`    fn new() -> Bar {    }}
impl Foo {    // Good. Return type contains `Self`    fn new() -> Result<Foo, FooError> {    }}

Or in a trait definition:

pub trait Trait {    // Bad. The type name must contain `Self`    fn new();}
pub trait Trait {    // Good. Return type contains `Self`    fn new() -> Self;}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

new_without_default📋
stylewarn

What it does

Checks for public types with apub fn new() -> Self method and noimplementation ofDefault.

Why is this bad?

The user might expect to be able to useDefault as thetype can be constructed without arguments.

Example

pub struct Foo(Bar);impl Foo {    pub fn new() -> Self {        Foo(Bar::new())    }}

To fix the lint, add aDefault implementation that delegates tonew:

pub struct Foo(Bar);impl Default for Foo {    fn default() -> Self {        Foo::new()    }}

Past names

  • new_without_default_derive
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

no_effect📋
complexitywarn

What it does

Checks for statements which have no effect.

Why is this bad?

Unlike dead code, these statements are actuallyexecuted. However, as they have no effect, all they do is make the code lessreadable.

Example

0;
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

no_effect_replace📋
suspiciouswarn

What it does

Checks forreplace statements which have no effect.

Why is this bad?

It’s either a mistake or confusing.

Example

"1234".replace("12", "12");"1234".replacen("12", "12", 1);
Applicability:Unspecified(?)
Added in:1.63.0
Related Issues
View Source

no_effect_underscore_binding📋
pedanticallow

What it does

Checks for binding to underscore prefixed variable without side-effects.

Why is this bad?

Unlike dead code, these bindings are actuallyexecuted. However, as they have no effect and shouldn’t be used further on, all theydo is make the code less readable.

Example

let _i_serve_no_purpose = 1;
Applicability:Unspecified(?)
Added in:1.58.0
Related Issues
View Source

no_mangle_with_rust_abi📋
pedanticallow

What it does

Checks for Rust ABI functions with the#[no_mangle] attribute.

Why is this bad?

The Rust ABI is not stable, but in many simple cases matchesenough with the C ABI that it is possible to forget to addextern "C" to a function called from C. Changes to theRust ABI can break this at any point.

Example

 #[no_mangle] fn example(arg_one: u32, arg_two: usize) {}

Use instead:

 #[no_mangle] extern "C" fn example(arg_one: u32, arg_two: usize) {}
Applicability:MaybeIncorrect(?)
Added in:1.69.0
Related Issues
View Source

non_ascii_literal📋
restrictionallow

What it does

Checks for non-ASCII characters in string and char literals.

Why restrict this?

Yeah, we know, the 90’s called and wanted their charsetback. Even so, there still are editors and other programs out there thatdon’t work well with Unicode. So if the code is meant to be usedinternationally, on multiple operating systems, or has other portabilityrequirements, activating this lint could be useful.

Example

let x = String::from("€");

Use instead:

let x = String::from("\u{20ac}");
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

non_canonical_clone_impl📋
suspiciouswarn

What it does

Checks for non-canonical implementations ofClone whenCopy is already implemented.

Why is this bad?

If bothClone andCopy are implemented, they must agree. This can done by dereferencingself inClone’s implementation, which will avoid any possibility of the implementationsbecoming out of sync.

Example

#[derive(Eq, PartialEq)]struct A(u32);impl Clone for A {    fn clone(&self) -> Self {        Self(self.0)    }}impl Copy for A {}

Use instead:

#[derive(Eq, PartialEq)]struct A(u32);impl Clone for A {    fn clone(&self) -> Self {        *self    }}impl Copy for A {}

Past names

  • incorrect_clone_impl_on_copy_type
Applicability:MaybeIncorrect(?)
Added in:1.72.0
Related Issues
View Source

non_canonical_partial_ord_impl📋
suspiciouswarn

What it does

Checks for non-canonical implementations ofPartialOrd whenOrd is already implemented.

Why is this bad?

If bothPartialOrd andOrd are implemented, they must agree. This is commonly done bywrapping the result ofcmp inSome forpartial_cmp. Not doing this may silentlyintroduce an error upon refactoring.

Known issues

Code that calls the.into() method instead will be flagged, despite.into() wrapping itinSome.

Example

#[derive(Eq, PartialEq)]struct A(u32);impl Ord for A {    fn cmp(&self, other: &Self) -> Ordering {        // ...    }}impl PartialOrd for A {    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {        // ...    }}

Use instead:

#[derive(Eq, PartialEq)]struct A(u32);impl Ord for A {    fn cmp(&self, other: &Self) -> Ordering {        // ...    }}impl PartialOrd for A {    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {        Some(self.cmp(other))   // or self.cmp(other).into()    }}

Past names

  • incorrect_partial_ord_impl_on_ord_type
Applicability:Unspecified(?)
Added in:1.73.0
Related Issues
View Source

non_minimal_cfg📋
stylewarn

What it does

Checks forany andall combinators incfg with only one condition.

Why is this bad?

If there is only one condition, no need to wrap it intoany orall combinators.

Example

#[cfg(any(unix))]pub struct Bar;

Use instead:

#[cfg(unix)]pub struct Bar;
Applicability:MaybeIncorrect(?)
Added in:1.71.0
Related Issues
View Source

non_octal_unix_permissions📋
correctnessdeny

What it does

Checks for non-octal values used to set Unix file permissions.

Why is this bad?

They will be converted into octal, creating potentiallyunintended file permissions.

Example

use std::fs::OpenOptions;use std::os::unix::fs::OpenOptionsExt;let mut options = OpenOptions::new();options.mode(644);

Use instead:

use std::fs::OpenOptions;use std::os::unix::fs::OpenOptionsExt;let mut options = OpenOptions::new();options.mode(0o644);
Applicability:MachineApplicable(?)
Added in:1.53.0
Related Issues
View Source

non_send_fields_in_send_ty📋
nurseryallow

What it does

This lint warns about aSend implementation for a type thatcontains fields that are not safe to be sent across threads.It tries to detect fields that can cause a soundness issuewhen sent to another thread (e.g.,Rc) while allowing!Send fieldsthat are expected to exist in aSend type, such as raw pointers.

Why is this bad?

Sending the struct to another thread effectively sends all of its fields,and the fields that do not implementSend can lead to soundness bugssuch as data races when accessed in a threadthat is different from the thread that created it.

See:

Known Problems

This lint relies on heuristics to distinguish types that are actuallyunsafe to be sent across threads and!Send types that are expected toexist inSend type. Its rule can filter out basic cases such asVec<*const T>, but it’s not perfect. Feel free to create an issue ifyou have a suggestion on how this heuristic can be improved.

Example

struct ExampleStruct<T> {    rc_is_not_send: Rc<String>,    unbounded_generic_field: T,}// This impl is unsound because it allows sending `!Send` types through `ExampleStruct`unsafe impl<T> Send for ExampleStruct<T> {}

Use thread-safe types likestd::sync::Arcor specify correct bounds on generic type parameters (T: Send).

Configuration

  • enable-raw-pointer-heuristic-for-send: Whether to apply the raw pointer heuristic to determine if a type isSend.

    (default:true)

Applicability:Unspecified(?)
Added in:1.57.0
Related Issues
View Source

non_std_lazy_statics📋
pedanticallow

What it does

Lints whenonce_cell::sync::Lazy orlazy_static! are used to define a static variable,and suggests replacing such cases withstd::sync::LazyLock instead.

Note: This lint will not trigger in crate withno_std context, or with MSRV < 1.80.0. Italso will not trigger ononce_cell::sync::Lazy usage in crates which use other typesfromonce_cell, such asonce_cell::race::OnceBox.

Why restrict this?

  • Reduces the need for an extra dependency
  • Enforce convention of using standard library types when possible

Example

lazy_static! {    static ref FOO: String = "foo".to_uppercase();}static BAR: once_cell::sync::Lazy<String> = once_cell::sync::Lazy::new(|| "BAR".to_lowercase());

Use instead:

static FOO: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "FOO".to_lowercase());static BAR: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "BAR".to_lowercase());

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

non_zero_suggestions📋
restrictionallow

What it does

Checks for conversions fromNonZero types to regular integer types,and suggests usingNonZero types for the target as well.

Why is this bad?

Converting fromNonZero types to regular integer types and then back toNonZerotypes is less efficient and loses the type-safety guarantees provided byNonZero types.UsingNonZero types consistently can lead to more optimized code and preventcertain classes of errors related to zero values.

Example

use std::num::{NonZeroU32, NonZeroU64};fn example(x: u64, y: NonZeroU32) {    // Bad: Converting NonZeroU32 to u64 unnecessarily    let r1 = x / u64::from(y.get());    let r2 = x % u64::from(y.get());}

Use instead:

use std::num::{NonZeroU32, NonZeroU64};fn example(x: u64, y: NonZeroU32) {    // Good: Preserving the NonZero property    let r1 = x / NonZeroU64::from(y);    let r2 = x % NonZeroU64::from(y);}
Applicability:MachineApplicable(?)
Added in:1.83.0
Related Issues
View Source

nonminimal_bool📋
complexitywarn

What it does

Checks for boolean expressions that can be written moreconcisely.

Why is this bad?

Readability of boolean expressions suffers fromunnecessary duplication.

Known problems

Ignores short circuiting behavior of|| and&&. Ignores|,& and^.

Example

if a && true {}if !(a == b) {}

Use instead:

if a {}if a != b {}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

nonsensical_open_options📋
correctnessdeny

What it does

Checks for duplicate open options as well as combinationsthat make no sense.

Why is this bad?

In the best case, the code will be harder to read thannecessary. I don’t know the worst case.

Example

use std::fs::OpenOptions;OpenOptions::new().read(true).truncate(true);
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

nonstandard_macro_braces📋
nurseryallow

What it does

Checks that common macros are used with consistent bracing.

Why is this bad?

Having non-conventional braces on well-stablished macros can be confusingwhen debugging, and they bring incosistencies with the rest of the ecosystem.

Example

vec!{1, 2, 3};

Use instead:

vec![1, 2, 3];

Configuration

  • standard-macro-braces: Enforce the named macros always use the braces specified.

AMacroMatcher can be added like so{ name = "macro_name", brace = "(" }. If the macrocould be used with a full path twoMacroMatchers have to be added one with the full pathcrate_name::macro_name and one with just the macro name.

(default:[])

Applicability:MachineApplicable(?)
Added in:1.55.0
Related Issues
View Source

not_unsafe_ptr_arg_deref📋
correctnessdeny

What it does

Checks for public functions that dereference raw pointerarguments but are not markedunsafe.

Why is this bad?

The function should almost definitely be markedunsafe, since for anarbitrary raw pointer, there is no way of telling for sure if it is valid.

In general, this lint shouldnever be disabled unless it is definitely afalse positive (please submit an issue if so) since it breaks Rust’ssoundness guarantees, directly exposing API users to potentially dangerousprogram behavior. This is also true for internal APIs, as it is easy to leakunsoundness.

Context

In Rust, anunsafe {...} block is used to indicate that the code in thatsection has been verified in some way that the compiler can not. For afunction that accepts a raw pointer then accesses the pointer’s data, this isgenerally impossible as the incoming pointer could point anywhere, valid ornot. So, the signature should be markedunsafe fn: this indicates that thefunction’s caller must provide some verification that the arguments it sendsare valid (and then call the function within anunsafe block).

Known problems

  • It does not check functions recursively so if the pointer is passed to aprivate non-unsafe function which does the dereferencing, the lint won’ttrigger (false negative).
  • It only checks for arguments whose type are raw pointers, not raw pointersgot from an argument in some other way (fn foo(bar: &[*const u8]) orsome_argument.get_raw_ptr()) (false negative).

Example

pub fn foo(x: *const u8) {    println!("{}", unsafe { *x });}// this call "looks" safe but will segfault or worse!// foo(invalid_ptr);

Use instead:

pub unsafe fn foo(x: *const u8) {    println!("{}", unsafe { *x });}// this would cause a compiler error for calling without `unsafe`// foo(invalid_ptr);// sound call if the caller knows the pointer is validunsafe { foo(valid_ptr); }
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

obfuscated_if_else📋
stylewarn

What it does

Checks for unnecessary method chains that can be simplified intoif .. else ...

Why is this bad?

This can be written more clearly withif .. else ..

Limitations

This lint currently only looks for usages of.{then, then_some}(..).{unwrap_or, unwrap_or_else, unwrap_or_default}(..), but will be expandedto account for similar patterns.

Example

let x = true;x.then_some("a").unwrap_or("b");

Use instead:

let x = true;if x { "a" } else { "b" };
Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

octal_escapes📋
suspiciouswarn

What it does

Checks for\0 escapes in string and byte literals that look like octalcharacter escapes in C.

Why is this bad?

C and other languages support octal character escapes in strings, wherea backslash is followed by up to three octal digits. For example,\033stands for the ASCII character 27 (ESC). Rust does not support thisnotation, but has the escape code\0 which stands for a nullbyte/character, and any following digits do not form part of the escapesequence. Therefore,\033 is not a compiler error but the result maybe surprising.

Known problems

The actual meaning can be the intended one.\x00 can be used in thesecases to be unambiguous.

The lint does not trigger for format strings inprint!(),write!()and friends since the string is already preprocessed when Clippy lintscan see it.

Example

let one = "\033[1m Bold? \033[0m";  // \033 intended as escapelet two = "\033\0";                 // \033 intended as null-3-3

Use instead:

let one = "\x1b[1mWill this be bold?\x1b[0m";let two = "\x0033\x00";
Applicability:MaybeIncorrect(?)
Added in:1.59.0
Related Issues
View Source

ok_expect📋
stylewarn

What it does

Checks for usage ofok().expect(..).

Note: This lint only triggers for code marked compatiblewith versions of the compiler older than Rust 1.82.0.

Why is this bad?

Because you usually callexpect() on theResultdirectly to get a better error message.

Example

x.ok().expect("why did I do this again?");

Use instead:

x.expect("why did I do this again?");
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

only_used_in_recursion📋
complexitywarn

What it does

Checks for arguments that are only used in recursion with no side-effects.

Why is this bad?

It could contain a useless calculation and can make function simpler.

The arguments can be involved in calculations and assignments but as long asthe calculations have no side-effects (function calls or mutating dereference)and the assigned variables are also only in recursion, it is useless.

Example

fn f(a: usize, b: usize) -> usize {    if a == 0 {        1    } else {        f(a - 1, b + 1)    }}

Use instead:

fn f(a: usize) -> usize {    if a == 0 {        1    } else {        f(a - 1)    }}

Known problems

Too many code paths in the linting code are currently untested and prone to produce falsepositives or are prone to have performance implications.

In some cases, this would not catch all useless arguments.

fn foo(a: usize, b: usize) -> usize {    let f = |x| x + 1;    if a == 0 {        1    } else {        foo(a - 1, f(b))    }}

For example, the argumentb is only used in recursion, but the lint would not catch it.

List of some examples that can not be caught:

  • binary operation of non-primitive types
  • closure usage
  • somebreak relative operations
  • struct pattern binding

Also, when you recurse the function name with path segments, it is not possible to detect.

Applicability:MaybeIncorrect(?)
Added in:1.61.0
Related Issues
View Source

op_ref📋
stylewarn

What it does

Checks for arguments to== which have their addresstaken to satisfy a boundand suggests to dereference the other argument instead

Why is this bad?

It is more idiomatic to dereference the other argument.

Example

&x == y

Use instead:

x == *y
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

option_as_ref_cloned📋
pedanticallow

What it does

Checks for usage of.as_ref().cloned() and.as_mut().cloned() onOptions

Why is this bad?

This can be written more concisely by cloning theOption directly.

Example

fn foo(bar: &Option<Vec<u8>>) -> Option<Vec<u8>> {    bar.as_ref().cloned()}

Use instead:

fn foo(bar: &Option<Vec<u8>>) -> Option<Vec<u8>> {    bar.clone()}
Applicability:MachineApplicable(?)
Added in:1.77.0
Related Issues
View Source

option_as_ref_deref📋
complexitywarn

What it does

Checks for usage of_.as_ref().map(Deref::deref) or its aliases (such as String::as_str).

Why is this bad?

Readability, this can be written more concisely as_.as_deref().

Example

opt.as_ref().map(String::as_str)

Can be written as

opt.as_deref()

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.42.0
Related Issues
View Source

option_env_unwrap📋
correctnessdeny

What it does

Checks for usage ofoption_env!(...).unwrap() andsuggests usage of theenv! macro.

Why is this bad?

Unwrapping the result ofoption_env! will panicat run-time if the environment variable doesn’t exist, whereasenv!catches it at compile-time.

Example

let _ = option_env!("HOME").unwrap();

Is better expressed as:

let _ = env!("HOME");
Applicability:Unspecified(?)
Added in:1.43.0
Related Issues
View Source

option_filter_map📋
complexitywarn

What it does

Checks for iterators ofOptions using.filter(Option::is_some).map(Option::unwrap) that maybe replaced with a.flatten() call.

Why is this bad?

Option is like a collection of 0-1 things, soflattenautomatically does this without suspicious-lookingunwrap calls.

Example

let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);

Use instead:

let _ = std::iter::empty::<Option<i32>>().flatten();
Applicability:MachineApplicable(?)
Added in:1.53.0
Related Issues
View Source

option_if_let_else📋
nurseryallow

What it does

Lints usage ofif let Some(v) = ... { y } else { x } andmatch .. { Some(v) => y, None/_ => x } which are moreidiomatically done withOption::map_or (if the else bit is a pureexpression) orOption::map_or_else (if the else bit is an impureexpression).

Why is this bad?

Using the dedicated functions of theOption type is clearer andmore concise than anif let expression.

Notes

This lint uses a deliberately conservative metric for checking if theinside of either body contains loop control expressionsbreak orcontinue (which cannot be used within closures). If these are found,this lint will not be raised.

Example

let _ = if let Some(foo) = optional {    foo} else {    5};let _ = match optional {    Some(val) => val + 1,    None => 5};let _ = if let Some(foo) = optional {    foo} else {    let y = do_complicated_function();    y*y};

should be

let _ = optional.map_or(5, |foo| foo);let _ = optional.map_or(5, |val| val + 1);let _ = optional.map_or_else(||{    let y = do_complicated_function();    y*y}, |foo| foo);
Applicability:MaybeIncorrect(?)
Added in:1.47.0
Related Issues
View Source

option_map_or_err_ok📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

clippy::manual_ok_or covers this case.

Applicability:Unspecified(?)
Deprecated in:1.87.0
Related Issues

option_map_or_none📋
stylewarn

What it does

Checks for usage of_.map_or(None, _).

Why is this bad?

Readability, this can be written more concisely as_.and_then(_).

Known problems

The order of the arguments is not in execution order.

Example

opt.map_or(None, |a| Some(a + 1));

Use instead:

opt.and_then(|a| Some(a + 1));
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

option_map_unit_fn📋
complexitywarn

What it does

Checks for usage ofoption.map(f) where f is a functionor closure that returns the unit type().

Why is this bad?

Readability, this can be written more clearly withan if let statement

Example

let x: Option<String> = do_stuff();x.map(log_err_msg);x.map(|msg| log_err_msg(format_msg(msg)));

The correct use would be:

let x: Option<String> = do_stuff();if let Some(msg) = x {    log_err_msg(msg);}if let Some(msg) = x {    log_err_msg(format_msg(msg));}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

option_option📋
pedanticallow

What it does

Checks for usage ofOption<Option<_>> in function signatures and typedefinitions

Why is this bad?

Option<_> represents an optional value.Option<Option<_>>represents an optional value which itself wraps an optional. This is logically thesame thing as an optional value but has an unneeded extra level of wrapping.

If you have a case whereSome(Some(_)),Some(None) andNone are distinct cases,consider a customenum instead, with clear names for each case.

Example

fn get_data() -> Option<Option<u32>> {    None}

Better:

pub enum Contents {    Data(Vec<u8>), // Was Some(Some(Vec<u8>))    NotYetFetched, // Was Some(None)    None,          // Was None}fn get_data() -> Contents {    Contents::None}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

or_fun_call📋
nurseryallow

What it does

Checks for calls to.or(foo(..)),.unwrap_or(foo(..)),.or_insert(foo(..)) etc., and suggests to use.or_else(|| foo(..)),.unwrap_or_else(|| foo(..)),.unwrap_or_default() or.or_default()etc. instead.

Why is this bad?

The function will always be called. This is only bad if it allocates ordoes some non-trivial amount of work.

Known problems

If the function has side-effects, not calling it will change thesemantic of the program, but you shouldn’t rely on that.

The lint also cannot figure out whether the function you call isactually expensive to call or not.

Example

foo.unwrap_or(String::from("empty"));

Use instead:

foo.unwrap_or_else(|| String::from("empty"));

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:HasPlaceholders(?)
Added in:pre 1.29.0
Related Issues
View Source

or_then_unwrap📋
complexitywarn

What it does

Checks for.or(…).unwrap() calls to Options and Results.

Why is this bad?

You should use.unwrap_or(…) instead for clarity.

Example

// Resultlet value = result.or::<Error>(Ok(fallback)).unwrap();// Optionlet value = option.or(Some(fallback)).unwrap();

Use instead:

// Resultlet value = result.unwrap_or(fallback);// Optionlet value = option.unwrap_or(fallback);
Applicability:MachineApplicable(?)
Added in:1.61.0
Related Issues
View Source

out_of_bounds_indexing📋
correctnessdeny

What it does

Checks for out of bounds array indexing with a constantindex.

Why is this bad?

This will always panic at runtime.

Example

let x = [1, 2, 3, 4];x[9];&x[2..9];

Use instead:

// Index within boundsx[0];x[3];
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

overly_complex_bool_expr📋
correctnessdeny

What it does

Checks for boolean expressions that contain terminals thatcan be eliminated.

Why is this bad?

This is most likely a logic bug.

Known problems

Ignores short circuiting behavior.

Example

// The `b` is unnecessary, the expression is equivalent to `if a`.if a && b || a { ... }

Use instead:

if a {}

Past names

  • logic_bug
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

owned_cow📋
stylewarn

What it does

Detects needlessly ownedCow types.

Why is this bad?

The borrowed types are usually more flexible, in that e.g. aCow<'_, str> can accept both&str andString whileCow<'_, String> can only accept&String andString. Inparticular,&str is more general, because it allows for stringliterals while&String can only be borrowed from a heap-ownedString).

Known Problems

The lint does not check for usage of the type. There may be externalinterfaces that require the use of an owned type.

At least theCString type also has a different API thanCStr: Theformer has anas_bytes method which the latter callsto_bytes.There is no guarantee that other types won’t gain additional methodsleading to a similar mismatch.

In addition, the lint only checks for the known problematic typesString,Vec<_>,CString,OsString andPathBuf. Custom typesthat implementToOwned will not be detected.

Example

let wrogn: std::borrow::Cow<'_, Vec<u8>>;

Use instead:

let right: std::borrow::Cow<'_, [u8]>;

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:1.87.0
Related Issues
View Source

panic📋
restrictionallow

What it does

Checks for usage ofpanic!.

Why restrict this?

This macro, or panics in general, may be unwanted in production code.

Example

panic!("even with a good reason");

Configuration

  • allow-panic-in-tests: Whetherpanic should be allowed in test functions or#[cfg(test)]

    (default:false)

Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

panic_in_result_fn📋
restrictionallow

What it does

Checks for usage ofpanic! or assertions in a function whose return type isResult.

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

Functions called from a function returning aResult may invoke a panicking macro. This is not checked.

Example

fn result_with_panic() -> Result<bool, String>{    panic!("error");}

Use instead:

fn result_without_panic() -> Result<bool, String> {    Err(String::from("error"))}
Applicability:Unspecified(?)
Added in:1.48.0
Related Issues
View Source

panicking_overflow_checks📋
correctnessdeny

What it does

Detects C-style underflow/overflow checks.

Why is this bad?

These checks will, by default, panic in debug builds rather than checkwhether the operation caused an overflow.

Example

if a + b < a {    // handle overflow}

Use instead:

if a.checked_add(b).is_none() {    // handle overflow}

Or:

if a.overflowing_add(b).1 {    // handle overflow}

Past names

  • overflow_check_conditional
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

panicking_unwrap📋
correctnessdeny

What it does

Checks for calls ofunwrap[_err]() that will always fail.

Why is this bad?

If panicking is desired, an explicitpanic!() should be used.

Known problems

This lint only checksif conditions not assignments.So something likelet x: Option<()> = None; x.unwrap(); will not be recognized.

Example

if option.is_none() {    do_something_with(option.unwrap())}

This code will always panic. The if condition should probably be inverted.

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

partial_pub_fields📋
restrictionallow

What it does

Checks whether some but not all fields of astruct are public.

Either make all fields of a type public, or make none of them public

Why restrict this?

Most types should either be:

  • Abstract data types: complex objects with opaque implementation which guardinterior 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

pub struct Color {    pub r: u8,    pub g: u8,    b: u8,}

Use instead:

pub struct Color {    pub r: u8,    pub g: u8,    pub b: u8,}
Applicability:Unspecified(?)
Added in:1.66.0
Related Issues
View Source

partialeq_ne_impl📋
complexitywarn

What it does

Checks for manual re-implementations ofPartialEq::ne.

Why is this bad?

PartialEq::ne is required to always return thenegated result ofPartialEq::eq, which is exactly what the defaultimplementation does. Therefore, there should never be any need tore-implement it.

Example

struct Foo;impl PartialEq for Foo {    fn eq(&self, other: &Foo) -> bool { true }    fn ne(&self, other: &Foo) -> bool { !(self == other) }}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

partialeq_to_none📋
stylewarn

What it does

Checks for binary comparisons to a literalOption::None.

Why is this bad?

A programmer checking if somefoo isNone via a comparisonfoo == Noneis usually inspired from other programming languages (e.g.foo is Nonein Python).Checking if a value of typeOption<T> is (not) equal toNone in thatway relies onT: PartialEq to do the comparison, which is unneeded.

Example

fn foo(f: Option<u32>) -> &'static str {    if f != None { "yay" } else { "nay" }}

Use instead:

fn foo(f: Option<u32>) -> &'static str {    if f.is_some() { "yay" } else { "nay" }}
Applicability:MachineApplicable(?)
Added in:1.65.0
Related Issues
View Source

path_buf_push_overwrite📋
nurseryallow

What it does

  • Checks forpushcalls onPathBuf that can cause overwrites.

Why is this bad?

Callingpush with a root path at the start can overwrite theprevious defined path.

Example

use std::path::PathBuf;let mut x = PathBuf::from("/foo");x.push("/bar");assert_eq!(x, PathBuf::from("/bar"));

Could be written:

use std::path::PathBuf;let mut x = PathBuf::from("/foo");x.push("bar");assert_eq!(x, PathBuf::from("/foo/bar"));
Applicability:MaybeIncorrect(?)
Added in:1.36.0
Related Issues
View Source

path_ends_with_ext📋
suspiciouswarn

What it does

Looks for calls toPath::ends_with calls where the argument looks like a file extension.

By default, Clippy has a short list of known filenames that start with a dotbut aren’t necessarily file extensions (e.g. the.git folder), which are allowed by default.Theallowed-dotfiles configuration can be used to allow additionalfile extensions that Clippy should not lint.

Why is this bad?

This doesn’t actually compare file extensions. Rather,ends_with compares the given argumentto the lastcomponent of the path and checks if it matches exactly.

Known issues

File extensions are often at most three characters long, so this only lints in those casesin an attempt to avoid false positives.Any extension names longer than that are assumed to likely be real path components and aretherefore ignored.

Example

fn is_markdown(path: &Path) -> bool {    path.ends_with(".md")}

Use instead:

fn is_markdown(path: &Path) -> bool {    path.extension().is_some_and(|ext| ext == "md")}

Configuration

  • allowed-dotfiles: Additional dotfiles (files or directories starting with a dot) to allow

    (default:[])

Applicability:MaybeIncorrect(?)
Added in:1.74.0
Related Issues
View Source

pathbuf_init_then_push📋
restrictionallow

What it does

Checks for calls topush immediately after creating a newPathBuf.

Why is this bad?

Multiple.join() calls are usually easier to read than multiple.pushcalls across multiple statements. It might also be possible to usePathBuf::from instead.

Known problems

.join() introduces an implicitclone().PathBuf::from can alternatively beused when thePathBuf is newly constructed. This will avoid the implicit clone.

Example

let mut path_buf = PathBuf::new();path_buf.push("foo");

Use instead:

let path_buf = PathBuf::from("foo");// orlet path_buf = PathBuf::new().join("foo");
Applicability:HasPlaceholders(?)
Added in:1.82.0
Related Issues
View Source

pattern_type_mismatch📋
restrictionallow

What it does

Checks for patterns that aren’t exact representations of the typesthey are applied to.

To satisfy this lint, you will have to adjust either the expression that is matchedagainst or the pattern itself, as well as the bindings that are introduced by theadjusted patterns. For matching you will have to either dereference the expressionwith the* operator, or amend the patterns to explicitly match against&<pattern>or&mut <pattern> depending on the reference mutability. For the bindings you needto use the inverse. You can leave them as plain bindings if you wish for the valueto be copied, but you must useref mut <variable> orref <variable> to constructa reference into the matched structure.

If you are looking for a way to learn about ownership semantics in more detail, itis recommended to look at IDE options available to you to highlight types, lifetimesand reference semantics in your code. The available tooling would expose these thingsin a general way even outside of the various pattern matching mechanics. Of coursethis lint can still be used to highlight areas of interest and ensure a good understandingof ownership semantics.

Why restrict this?

It increases ownership hints in the code, and will guard against some changesin ownership.

Example

This example shows the basic adjustments necessary to satisfy the lint. Note howthe matched expression is explicitly dereferenced with* and theinner variableis bound to a shared borrow viaref inner.

// Badlet value = &Some(Box::new(23));match value {    Some(inner) => println!("{}", inner),    None => println!("none"),}// Goodlet value = &Some(Box::new(23));match *value {    Some(ref inner) => println!("{}", inner),    None => println!("none"),}

The following example demonstrates one of the advantages of the more verbose style.Note how the second version usesref mut a to explicitly declarea a shared mutableborrow, whileb is simply taken by value. This ensures that the loop body cannotaccidentally modify the wrong part of the structure.

// Badlet mut values = vec![(2, 3), (3, 4)];for (a, b) in &mut values {    *a += *b;}// Goodlet mut values = vec![(2, 3), (3, 4)];for &mut (ref mut a, b) in &mut values {    *a += b;}
Applicability:Unspecified(?)
Added in:1.47.0
Related Issues
View Source

permissions_set_readonly_false📋
suspiciouswarn

What it does

Checks for calls tostd::fs::Permissions.set_readonly with argumentfalse.

Why is this bad?

On Unix platforms this results in the file being world writable,equivalent tochmod a+w <file>.

Example

use std::fs::File;let f = File::create("foo.txt").unwrap();let metadata = f.metadata().unwrap();let mut permissions = metadata.permissions();permissions.set_readonly(false);
Applicability:Unspecified(?)
Added in:1.68.0
Related Issues
View Source

pointer_format📋
restrictionallow

What it does

Detectspointer format as well asDebug formatting of raw pointers or function pointersor any types that have a derivedDebug impl that recursively contains them.

Why restrict this?

The addresses are only useful in very specific contexts, and certain projects may want to keep addresses ofcertain data structures or functions from prying hacker eyes as an additional line of security.

Known problems

The lint currently only looks through derivedDebug implementations. Checking whether a manualimplementation prints an address is left as an exercise to the next lint implementer.

Example

let foo = &0_u32;fn bar() {}println!("{:p}", foo);let _ = format!("{:?}", &(bar as fn()));
Applicability:Unspecified(?)
Added in:1.89.0
Related Issues
View Source

pointers_in_nomem_asm_block📋
suspiciouswarn

What it does

Checks if any pointer is being passed to an asm! block withnomem option.

Why is this bad?

nomem forbids any reads or writes to memory and passing a pointer suggeststhat either of those will happen.

Example

fn f(p: *mut u32) {    unsafe { core::arch::asm!("mov [{p}], 42", p = in(reg) p, options(nomem, nostack)); }}

Use instead:

fn f(p: *mut u32) {    unsafe { core::arch::asm!("mov [{p}], 42", p = in(reg) p, options(nostack)); }}
Applicability:Unspecified(?)
Added in:1.81.0
Related Issues
View Source

possible_missing_comma📋
correctnessdeny

What it does

Checks for possible missing comma in an array. It lints ifan array element is a binary operator expression and it lies on two lines.

Why is this bad?

This could lead to unexpected results.

Example

let a = &[    -1, -2, -3 // <= no comma here    -4, -5, -6];
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

possible_missing_else📋
suspiciouswarn

What it does

Checks for anif expression followed by either a block or anotherif thatlooks like it should have anelse between them.

Why is this bad?

This is probably some refactoring remnant, even if the code is correct, itmight look confusing.

Example

if foo {} { // looks like an `else` is missing here}if foo {} if bar { // looks like an `else` is missing here}
Applicability:Unspecified(?)
Added in:1.91.0
Related Issues
View Source

precedence📋
complexitywarn

What it does

Checks for operations where precedence may be unclear and suggests to add parentheses.It catches a mixed usage of arithmetic and bit shifting/combining operators,as well as method calls applied to closures.

Why is this bad?

Not everyone knows the precedence of those operators byheart, so expressions like these may trip others trying to reason about thecode.

Example

1 << 2 + 3 equals 32, while(1 << 2) + 3 equals 7

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

precedence_bits📋
restrictionallow

What it does

Checks for bit shifting operations combined with bit masking/combining operatorsand suggest using parentheses.

Why restrict this?

Not everyone knows the precedence of those operators byheart, so expressions like these may trip others trying to reason about thecode.

Example

0x2345 & 0xF000 >> 12 equals 5, while(0x2345 & 0xF000) >> 12 equals 2

Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

print_in_format_impl📋
suspiciouswarn

What it does

Checks for usage ofprintln,print,eprintln oreprint in animplementation of a formatting trait.

Why is this bad?

Using a print macro is likely unintentional since formatting traitsshould write to theFormatter, not stdout/stderr.

Example

use std::fmt::{Display, Error, Formatter};struct S;impl Display for S {    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {        println!("S");        Ok(())    }}

Use instead:

use std::fmt::{Display, Error, Formatter};struct S;impl Display for S {    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {        writeln!(f, "S");        Ok(())    }}
Applicability:HasPlaceholders(?)
Added in:1.61.0
Related Issues
View Source

print_literal📋
stylewarn

What it does

This lint warns about the use of literals asprint!/println! args.

Why is this bad?

Using literals asprintln! args is inefficient(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary(i.e., just put the literal in the format string)

Example

println!("{}", "foo");

use the literal without formatting:

println!("foo");
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

print_stderr📋
restrictionallow

What it does

Checks for printing onstderr. The purpose of this lintis to catch debugging remnants.

Why restrict this?

People often print onstderr while debugging anapplication and might forget to remove those prints afterward.

Known problems

Only catcheseprint! andeprintln! calls.

Example

eprintln!("Hello world!");

Configuration

  • allow-print-in-tests: Whether print macros (ex.println!) should be allowed in test functions or#[cfg(test)]

    (default:false)

Applicability:Unspecified(?)
Added in:1.50.0
Related Issues
View Source

print_stdout📋
restrictionallow

What it does

Checks for printing onstdout. The purpose of this lintis to catch debugging remnants.

Why restrict this?

People often print onstdout while debugging anapplication and might forget to remove those prints afterward.

Known problems

Only catchesprint! andprintln! calls.

Example

println!("Hello world!");

Configuration

  • allow-print-in-tests: Whether print macros (ex.println!) should be allowed in test functions or#[cfg(test)]

    (default:false)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

print_with_newline📋
stylewarn

What it does

This lint warns when you useprint!() with a formatstring that ends in a newline.

Why is this bad?

You should useprintln!() instead, which appends thenewline.

Example

print!("Hello {}!\n", name);

use println!() instead

println!("Hello {}!", name);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

println_empty_string📋
stylewarn

What it does

This lint warns when you useprintln!("") toprint a newline.

Why is this bad?

You should useprintln!(), which is simpler.

Example

println!("");

Use instead:

println!();
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

ptr_arg📋
stylewarn

What it does

This lint checks for function arguments of type&String,&Vec,&PathBuf, andCow<_>. It will also suggest you replace.clone() callswith the appropriate.to_owned()/to_string() calls.

Why is this bad?

Requiring the argument to be of the specific typemakes the function less useful for no benefit; slices in the form of&[T]or&str usually suffice and can be obtained from other types, too.

Known problems

There may befn(&Vec)-typed references pointing to your function.If you have them, you will get a compiler error after applying this lint’ssuggestions. You then have the choice to undo your changes or change thetype of the reference.

Note that if the function is part of your public interface, there may beother crates referencing it, of which you may not be aware. Carefullydeprecate the function before applying the lint suggestions in this case.

Example

fn foo(&Vec<u32>) { .. }

Use instead:

fn foo(&[u32]) { .. }
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

ptr_as_ptr📋
pedanticallow

What it does

Checks foras casts between raw pointers that don’t change theirconstness, namely*const T to*const U and*mut T to*mut U.

Why is this bad?

Thoughas casts between raw pointers are not terrible,pointer::cast is safer because it cannot accidentally change thepointer’s mutability, nor cast the pointer to other types likeusize.

Example

let ptr: *const u32 = &42_u32;let mut_ptr: *mut u32 = &mut 42_u32;let _ = ptr as *const i32;let _ = mut_ptr as *mut i32;

Use instead:

let ptr: *const u32 = &42_u32;let mut_ptr: *mut u32 = &mut 42_u32;let _ = ptr.cast::<i32>();let _ = mut_ptr.cast::<i32>();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.51.0
Related Issues
View Source

ptr_cast_constness📋
pedanticallow

What it does

Checks foras casts between raw pointers that change their constness, namely*const T to*mut T and*mut T to*const T.

Why is this bad?

Thoughas casts between raw pointers are not terrible,pointer::cast_mut andpointer::cast_const are safer because they cannot accidentally cast the pointer to anothertype. Or, when null pointers are involved,null() andnull_mut() can be used directly.

Example

let ptr: *const u32 = &42_u32;let mut_ptr = ptr as *mut u32;let ptr = mut_ptr as *const u32;let ptr1 = std::ptr::null::<u32>() as *mut u32;let ptr2 = std::ptr::null_mut::<u32>() as *const u32;let ptr3 = std::ptr::null::<u32>().cast_mut();let ptr4 = std::ptr::null_mut::<u32>().cast_const();

Use instead:

let ptr: *const u32 = &42_u32;let mut_ptr = ptr.cast_mut();let ptr = mut_ptr.cast_const();let ptr1 = std::ptr::null_mut::<u32>();let ptr2 = std::ptr::null::<u32>();let ptr3 = std::ptr::null_mut::<u32>();let ptr4 = std::ptr::null::<u32>();
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

ptr_eq📋
stylewarn

What it does

Usestd::ptr::eq when applicable

Why is this bad?

ptr::eq can be used to compare&T references(which coerce to*const T implicitly) by their address rather thancomparing the values they point to.

Example

let a = &[1, 2, 3];let b = &[1, 2, 3];assert!(a as *const _ as usize == b as *const _ as usize);

Use instead:

let a = &[1, 2, 3];let b = &[1, 2, 3];assert!(std::ptr::eq(a, b));
Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

ptr_offset_with_cast📋
complexitywarn

What it does

Checks for usage of theoffset pointer method with ausize casted to anisize.

Why is this bad?

If we’re always increasing the pointer address, we can avoid the numericcast by using theadd method instead.

Example

let vec = vec![b'a', b'b', b'c'];let ptr = vec.as_ptr();let offset = 1_usize;unsafe {    ptr.offset(offset as isize);}

Could be written:

let vec = vec![b'a', b'b', b'c'];let ptr = vec.as_ptr();let offset = 1_usize;unsafe {    ptr.add(offset);}
Applicability:MachineApplicable(?)
Added in:1.30.0
Related Issues
View Source

pub_enum_variant_names📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

clippy::enum_variant_names now covers this case via theavoid-breaking-exported-api config.

Applicability:Unspecified(?)
Deprecated in:1.54.0
Related Issues

pub_underscore_fields📋
pedanticallow

What it does

Checks whether any field of the struct is prefixed with an_ (underscore) and also markedpub (public)

Why is this bad?

Fields prefixed with an_ are inferred as unused, which suggests it should not be markedaspub, because marking it aspub infers it will be used.

Example

struct FileHandle {    pub _descriptor: usize,}

Use instead:

struct FileHandle {    _descriptor: usize,}

OR

struct FileHandle {    pub descriptor: usize,}

Configuration

  • pub-underscore-fields-behavior: Lint “public” fields in a struct that are prefixed with an underscore based on theirexported visibility, or whether they are marked as “pub”.

    (default:"PubliclyExported")

Applicability:Unspecified(?)
Added in:1.77.0
Related Issues
View Source

pub_use📋
restrictionallow

What it does

Restricts the usage ofpub use ...

Why restrict this?

A project may wish to limitpub use instances to preventunintentional exports, or to encourage placing exported items directly in public modules.

Example

pub mod outer {    mod inner {        pub struct Test {}    }    pub use inner::Test;}use outer::Test;

Use instead:

pub mod outer {    pub struct Test {}}use outer::Test;
Applicability:Unspecified(?)
Added in:1.62.0
Related Issues
View Source

pub_with_shorthand📋
restrictionallow

What it does

Checks for usage ofpub(<loc>) within.

Why restrict this?

Consistency. Use it or don’t, just be consistent about it.

Also see thepub_without_shorthand lint for an alternative.

Example

pub(super) type OptBox<T> = Option<Box<T>>;

Use instead:

pub(in super) type OptBox<T> = Option<Box<T>>;
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

pub_without_shorthand📋
restrictionallow

What it does

Checks for usage ofpub(<loc>) withoutin.

Note: As you cannot write a module’s path inpub(<loc>), this will only trigger onpub(super) and the like.

Why restrict this?

Consistency. Use it or don’t, just be consistent about it.

Also see thepub_with_shorthand lint for an alternative.

Example

pub(in super) type OptBox<T> = Option<Box<T>>;

Use instead:

pub(super) type OptBox<T> = Option<Box<T>>;
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

question_mark📋
stylewarn

What it does

Checks for expressions that could be replaced by the? operator.

Why is this bad?

Using the? operator is shorter and more idiomatic.

Example

if option.is_none() {    return None;}

Could be written:

option?;

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

question_mark_used📋
restrictionallow

What it does

Checks for expressions that use the? operator and rejects them.

Why restrict this?

Sometimes code wants to avoid the? operator because for instance a localblock requires a macro to re-throw errors to attach additional information to theerror.

Example

let result = expr?;

Could be written:

utility_macro!(expr);
Applicability:Unspecified(?)
Added in:1.69.0
Related Issues
View Source

range_minus_one📋
pedanticallow

What it does

Checks for inclusive ranges where 1 is subtracted fromthe upper bound, e.g.,x..=(y-1).

Why is this bad?

The code is more readable with an exclusive rangelikex..y.

Limitations

The lint is conservative and will trigger only when switchingfrom an inclusive to an exclusive range is provably safe froma typing point of view. This corresponds to situations wherethe range is used as an iterator, or for indexing.

Example

for i in x..=(y-1) {    // ..}

Use instead:

for i in x..y {    // ..}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

range_plus_one📋
pedanticallow

What it does

Checks for exclusive ranges where 1 is added to theupper bound, e.g.,x..(y+1).

Why is this bad?

The code is more readable with an inclusive rangelikex..=y.

Limitations

The lint is conservative and will trigger only when switchingfrom an exclusive to an inclusive range is provably safe froma typing point of view. This corresponds to situations wherethe range is used as an iterator, or for indexing.

Known problems

Will add unnecessary pair of parentheses when theexpression is not wrapped in a pair but starts with an opening parenthesisand ends with a closing one.I.e.,let _ = (f()+1)..(f()+1) results inlet _ = ((f()+1)..=f()).

Also in many cases, inclusive ranges are still slower to run thanexclusive ranges, because they essentially add an extra branch thatLLVM may fail to hoist out of the loop.

Example

for i in x..(y+1) {    // ..}

Use instead:

for i in x..=y {    // ..}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

range_step_by_zero📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

Iterator::step_by(0) now panics and is no longer an infinite iterator.

Applicability:Unspecified(?)
Deprecated in:pre 1.29.0
Related Issues

range_zip_with_len📋
complexitywarn

What it does

Checks for zipping a collection with the range of0.._.len().

Why is this bad?

The code is better expressed with.enumerate().

Example

let _ = x.iter().zip(0..x.len());

Use instead:

let _ = x.iter().enumerate();
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

rc_buffer📋
restrictionallow

What it does

Checks forRc<T> andArc<T> whenT is a mutable buffer type such asString orVec.

Why restrict this?

Expressions such asRc<String> usually have no advantage overRc<str>, sinceit is larger and involves an extra level of indirection, and doesn’t implementBorrow<str>.

While mutating a buffer type would still be possible withRc::get_mut(), it onlyworks if there are no additional references yet, which usually defeats the purpose ofenclosing it in a shared ownership type. Instead, additionally wrapping the innertype with an interior mutable container (such asRefCell orMutex) would normallybe used.

Known problems

This pattern can be desirable to avoid the overhead of aRefCell orMutex forcases where mutation only happens before there are any additional references.

Example

fn foo(interned: Rc<String>) { ... }

Better:

fn foo(interned: Rc<str>) { ... }

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:1.48.0
Related Issues
View Source

rc_clone_in_vec_init📋
suspiciouswarn

What it does

Checks for reference-counted pointers (Arc,Rc,rc::Weak, andsync::Weak)invec![elem; len]

Why is this bad?

This will createelem once and clone itlen times - doing so withArc/Rc/Weakis a bit misleading, as it will create references to the same pointer, ratherthan different instances.

Example

let v = vec![std::sync::Arc::new("some data".to_string()); 100];// orlet v = vec![std::rc::Rc::new("some data".to_string()); 100];

Use instead:

// Initialize each value separately:let mut data = Vec::with_capacity(100);for _ in 0..100 {    data.push(std::rc::Rc::new("some data".to_string()));}// Or if you want clones of the same reference,// Create the reference beforehand to clarify that// it should be cloned for each valuelet data = std::rc::Rc::new("some data".to_string());let v = vec![data; 100];
Applicability:HasPlaceholders(?)
Added in:1.63.0
Related Issues
View Source

rc_mutex📋
restrictionallow

What it does

Checks forRc<Mutex<T>>.

Why restrict this?

Rc is used in single thread andMutex is used in multi thread.Consider usingRc<RefCell<T>> in single thread orArc<Mutex<T>> in multi thread.

Known problems

Sometimes combining generic types can lead to the requirement that atype use Rc in conjunction with Mutex. We must consider those cases false positives, butalas they are quite hard to rule out. Luckily they are also rare.

Example

use std::rc::Rc;use std::sync::Mutex;fn foo(interned: Rc<Mutex<i32>>) { ... }

Better:

use std::rc::Rc;use std::cell::RefCellfn foo(interned: Rc<RefCell<i32>>) { ... }

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:1.55.0
Related Issues
View Source

read_line_without_trim📋
correctnessdeny

What it does

Looks for calls to [Stdin::read_line] to read a line from the standard inputinto a string, then later attempting to use that string for an operation that will neverwork for strings with a trailing newline character in it (e.g. parsing into ai32).

Why is this bad?

The operation will always fail at runtime no matter what the user enters, thusmaking it a useless operation.

Example

let mut input = String::new();std::io::stdin().read_line(&mut input).expect("Failed to read a line");let num: i32 = input.parse().expect("Not a number!");assert_eq!(num, 42); // we never even get here!

Use instead:

let mut input = String::new();std::io::stdin().read_line(&mut input).expect("Failed to read a line");let num: i32 = input.trim_end().parse().expect("Not a number!");//                  ^^^^^^^^^^^ remove the trailing newlineassert_eq!(num, 42);
Applicability:MachineApplicable(?)
Added in:1.73.0
Related Issues
View Source

read_zero_byte_vec📋
nurseryallow

What it does

This lint catches reads into a zero-lengthVec.Especially in the case of a call towith_capacity, this lint warns that readgets the number of bytes from theVec’s length, not its capacity.

Why is this bad?

Reading zero bytes is almost certainly not the intended behavior.

Known problems

In theory, a very unusual read implementation could assign some semantic meaningto zero-byte reads. But it seems exceptionally unlikely that code intending to doa zero-byte read would allocate aVec for it.

Example

use std::io;fn foo<F: io::Read>(mut f: F) {    let mut data = Vec::with_capacity(100);    f.read(&mut data).unwrap();}

Use instead:

use std::io;fn foo<F: io::Read>(mut f: F) {    let mut data = Vec::with_capacity(100);    data.resize(100, 0);    f.read(&mut data).unwrap();}
Applicability:MaybeIncorrect(?)
Added in:1.63.0
Related Issues
View Source

readonly_write_lock📋
perfwarn

What it does

Looks for calls toRwLock::write where the lock is only used for reading.

Why is this bad?

The write portion ofRwLock is exclusive, meaning that no other threadcan access the lock while this writer is active.

Example

use std::sync::RwLock;fn assert_is_zero(lock: &RwLock<i32>) {    let num = lock.write().unwrap();    assert_eq!(*num, 0);}

Use instead:

use std::sync::RwLock;fn assert_is_zero(lock: &RwLock<i32>) {    let num = lock.read().unwrap();    assert_eq!(*num, 0);}
Applicability:MaybeIncorrect(?)
Added in:1.73.0
Related Issues
View Source

recursive_format_impl📋
correctnessdeny

What it does

Checks for format trait implementations (e.g.Display) with a recursive call to itselfwhich usesself as a parameter.This is typically done indirectly with thewrite! macro or withto_string().

Why is this bad?

This will lead to infinite recursion and a stack overflow.

Example

use std::fmt;struct Structure(i32);impl fmt::Display for Structure {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        write!(f, "{}", self.to_string())    }}

Use instead:

use std::fmt;struct Structure(i32);impl fmt::Display for Structure {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        write!(f, "{}", self.0)    }}

Past names

  • to_string_in_display
Applicability:Unspecified(?)
Added in:1.48.0
Related Issues
View Source

redundant_allocation📋
perfwarn

What it does

Checks for usage of redundant allocations anywhere in the code.

Why is this bad?

Expressions such asRc<&T>,Rc<Rc<T>>,Rc<Arc<T>>,Rc<Box<T>>,Arc<&T>,Arc<Rc<T>>,Arc<Arc<T>>,Arc<Box<T>>,Box<&T>,Box<Rc<T>>,Box<Arc<T>>,Box<Box<T>>, add an unnecessary level of indirection.

Example

fn foo(bar: Rc<&usize>) {}

Better:

fn foo(bar: &usize) {}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:MaybeIncorrect(?)
Added in:1.44.0
Related Issues
View Source

redundant_as_str📋
complexitywarn

What it does

Checks for usage ofas_str() on aString chained with a method available on theString itself.

Why is this bad?

Theas_str() conversion is pointless and can be removed for simplicity and cleanliness.

Example

let owned_string = "This is a string".to_owned();owned_string.as_str().as_bytes()

Use instead:

let owned_string = "This is a string".to_owned();owned_string.as_bytes()
Applicability:MachineApplicable(?)
Added in:1.74.0
Related Issues
View Source

redundant_async_block📋
complexitywarn

What it does

Checks forasync block that only returnsawait on a future.

Why is this bad?

It is simpler and more efficient to use the future directly.

Example

let f = async {    1 + 2};let fut = async {    f.await};

Use instead:

let f = async {    1 + 2};let fut = f;
Applicability:MachineApplicable(?)
Added in:1.70.0
Related Issues
View Source

redundant_at_rest_pattern📋
complexitywarn

What it does

Checks for[all @ ..] patterns.

Why is this bad?

In all cases,all works fine and can often make code simpler, as you possibly won’t needto convert from say aVec to a slice by dereferencing.

Example

if let [all @ ..] = &*v {    // NOTE: Type is a slice here    println!("all elements: {all:#?}");}

Use instead:

if let all = v {    // NOTE: Type is a `Vec` here    println!("all elements: {all:#?}");}// orprintln!("all elements: {v:#?}");
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

redundant_clone📋
nurseryallow

What it does

Checks for a redundantclone() (and its relatives) which clones an ownedvalue that is going to be dropped without further use.

Why is this bad?

It is not always possible for the compiler to eliminate uselessallocations and deallocations generated by redundantclone()s.

Known problems

False-negatives: analysis performed by this lint is conservative and limited.

Example

{    let x = Foo::new();    call(x.clone());    call(x.clone()); // this can just pass `x`}["lorem", "ipsum"].join(" ").to_string();Path::new("/a/b").join("c").to_path_buf();
Applicability:MachineApplicable(?)
Added in:1.32.0
Related Issues
View Source

redundant_closure📋
stylewarn

What it does

Checks for closures which just call another function wherethe function can be called directly.unsafe functions, calls where typesget adjusted or where the callee is marked#[track_caller] are ignored.

Why is this bad?

Needlessly creating a closure adds code for no benefitand gives the optimizer more work.

Example

xs.map(|x| foo(x))

Use instead:

// where `foo(_)` is a plain function that takes the exact argument type of `x`.xs.map(foo)
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

redundant_closure_call📋
complexitywarn

What it does

Detects closures called in the same expression where theyare defined.

Why is this bad?

It is unnecessarily adding to the expression’scomplexity.

Example

let a = (|| 42)();

Use instead:

let a = 42;
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

redundant_closure_for_method_calls📋
pedanticallow

What it does

Checks for closures which only invoke a method on the closureargument and can be replaced by referencing the method directly.

Why is this bad?

It’s unnecessary to create the closure.

Example

Some('a').map(|s| s.to_uppercase());

may be rewritten as

Some('a').map(char::to_uppercase);
Applicability:MachineApplicable(?)
Added in:1.35.0
Related Issues
View Source

redundant_comparisons📋
correctnessdeny

What it does

Checks for ineffective double comparisons against constants.

Why is this bad?

Only one of the comparisons has any effect on the result, the programmerprobably intended to flip one of the comparison operators, or compare adifferent value entirely.

Example

if status_code <= 400 && status_code < 500 {}
Applicability:Unspecified(?)
Added in:1.73.0
Related Issues
View Source

redundant_else📋
pedanticallow

What it does

Checks forelse blocks that can be removed without changing semantics.

Why is this bad?

Theelse block adds unnecessary indentation and verbosity.

Known problems

Some may prefer to keep theelse block for clarity.

Example

fn my_func(count: u32) {    if count == 0 {        print!("Nothing to do");        return;    } else {        print!("Moving on...");    }}

Use instead:

fn my_func(count: u32) {    if count == 0 {        print!("Nothing to do");        return;    }    print!("Moving on...");}
Applicability:MachineApplicable(?)
Added in:1.50.0
Related Issues
View Source

redundant_feature_names📋
cargoallow

What it does

Checks for feature names with prefixuse-,with- or suffix-support

Why is this bad?

These prefixes and suffixes have no significant meaning.

Example

[features]default = ["use-abc", "with-def", "ghi-support"]use-abc = []  // redundantwith-def = []   // redundantghi-support = []   // redundant

Use instead:

[features]default = ["abc", "def", "ghi"]abc = []def = []ghi = []
Applicability:Unspecified(?)
Added in:1.57.0
Related Issues
View Source

redundant_field_names📋
stylewarn

What it does

Checks for fields in struct literals where shorthandscould be used.

Why is this bad?

If the field and variable names are the same,the field name is redundant.

Example

let bar: u8 = 123;struct Foo {    bar: u8,}let foo = Foo { bar: bar };

the last line can be simplified to

let foo = Foo { bar };

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

redundant_guards📋
complexitywarn

What it does

Checks for unnecessary guards in match expressions.

Why is this bad?

It’s more complex and much less readable. Making it part of the pattern can improveexhaustiveness checking as well.

Example

match x {    Some(x) if matches!(x, Some(1)) => ..,    Some(x) if x == Some(2) => ..,    _ => todo!(),}

Use instead:

match x {    Some(Some(1)) => ..,    Some(Some(2)) => ..,    _ => todo!(),}
Applicability:MaybeIncorrect(?)
Added in:1.73.0
Related Issues
View Source

redundant_iter_cloned📋
perfwarn

What it does

Checks for calls toIterator::cloned where the original value could be usedinstead.

Why is this bad?

It is not always possible for the compiler to eliminate useless allocations anddeallocations generated by redundantclone()s.

Example

let x = vec![String::new()];let _ = x.iter().cloned().map(|x| x.len());

Use instead:

let x = vec![String::new()];let _ = x.iter().map(|x| x.len());
Applicability:MachineApplicable(?)
Added in:1.90.0
Related Issues
View Source

redundant_locals📋
suspiciouswarn

What it does

Checks for redundant redefinitions of local bindings.

Why is this bad?

Redundant redefinitions of local bindings do not change behavior other than variable’s lifetimes and are likely to be unintended.

These rebindings can be intentional to shorten the lifetimes of variables because they affect when theDrop implementation is called. Other than that, they do not affect your code’s meaning but theymay affectrustc’s stack allocation.

Example

let a = 0;let a = a;fn foo(b: i32) {    let b = b;}

Use instead:

let a = 0;// no redefinition with the same namefn foo(b: i32) {  // no redefinition with the same name}
Applicability:Unspecified(?)
Added in:1.73.0
Related Issues
View Source

redundant_pattern📋
stylewarn

What it does

Checks for patterns in the formname @ _.

Why is this bad?

It’s almost always more readable to just use directbindings.

Example

match v {    Some(x) => (),    y @ _ => (),}

Use instead:

match v {    Some(x) => (),    y => (),}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

redundant_pattern_matching📋
stylewarn

What it does

Lint for redundant pattern matching overResult,Option,std::task::Poll,std::net::IpAddr orbools

Why is this bad?

It’s more concise and clear to just use the properutility function or using the condition directly

Known problems

For suggestions involving bindings in patterns, this will change the drop order for the matched type.Bothif let andwhile let will drop the value at the end of the block, bothif andwhile will drop thevalue before entering the block. For most types this change will not matter, but for a fewtypes this will not be an acceptable change (e.g. locks). See thereference for more aboutdrop order.

Example

if let Ok(_) = Ok::<i32, i32>(42) {}if let Err(_) = Err::<i32, i32>(42) {}if let None = None::<()> {}if let Some(_) = Some(42) {}if let Poll::Pending = Poll::Pending::<()> {}if let Poll::Ready(_) = Poll::Ready(42) {}if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}match Ok::<i32, i32>(42) {    Ok(_) => true,    Err(_) => false,};let cond = true;if let true = cond {}matches!(cond, true);

The more idiomatic use would be:

if Ok::<i32, i32>(42).is_ok() {}if Err::<i32, i32>(42).is_err() {}if None::<()>.is_none() {}if Some(42).is_some() {}if Poll::Pending::<()>.is_pending() {}if Poll::Ready(42).is_ready() {}if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}Ok::<i32, i32>(42).is_ok();let cond = true;if cond {}cond;

Past names

  • if_let_redundant_pattern_matching
Applicability:MachineApplicable(?)
Added in:1.31.0
Related Issues
View Source

redundant_pub_crate📋
nurseryallow

What it does

Checks for items declaredpub(crate) that are not crate visible because theyare inside a private module.

Why is this bad?

Writingpub(crate) is misleading when it’s redundant due to the parentmodule’s visibility.

Example

mod internal {    pub(crate) fn internal_fn() { }}

This function is not visible outside the module and it can be declared withpub orprivate visibility

mod internal {    pub fn internal_fn() { }}
Applicability:MachineApplicable(?)
Added in:1.44.0
Related Issues
View Source

redundant_slicing📋
complexitywarn

What it does

Checks for redundant slicing expressions which use the full range, anddo not change the type.

Why is this bad?

It unnecessarily adds complexity to the expression.

Known problems

If the type being sliced has an implementation ofIndex<RangeFull>that actually changes anything then it can’t be removed. However, this would be surprisingto people reading the code and should have a note with it.

Example

fn get_slice(x: &[u32]) -> &[u32] {    &x[..]}

Use instead:

fn get_slice(x: &[u32]) -> &[u32] {    x}
Applicability:MachineApplicable(?)
Added in:1.51.0
Related Issues
View Source

redundant_static_lifetimes📋
stylewarn

What it does

Checks for constants and statics with an explicit'static lifetime.

Why is this bad?

Adding'static to every reference can create verycomplicated types.

Example

const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =&[...]static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =&[...]

This code can be rewritten as

 const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]

Past names

  • const_static_lifetime

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.37.0
Related Issues
View Source

redundant_test_prefix📋
restrictionallow

What it does

Checks for test functions (functions annotated with#[test]) that are prefixedwithtest_ which is redundant.

Why is this bad?

This is redundant because test functions are already annotated with#[test].Moreover, it clutters the output ofcargo test since test functions are expanded asmodule::tests::test_use_case in the output. Without the redundant prefix, the outputbecomesmodule::tests::use_case, which is more readable.

Example

#[cfg(test)]mod tests {  use super::*;  #[test]  fn test_use_case() {      // test code  }}

Use instead:

#[cfg(test)]mod tests {  use super::*;  #[test]  fn use_case() {      // test code  }}
Applicability:MaybeIncorrect(?)
Added in:1.88.0
Related Issues
View Source

redundant_type_annotations📋
restrictionallow

What it does

Warns about needless / redundant type annotations.

Why restrict this?

Code without type annotations is shorter and in most casesmore idiomatic and easier to modify.

Limitations

This lint doesn’t support:

  • Generics
  • Refs returned from anything else than aMethodCall
  • Complex types (tuples, arrays, etc…)
  • Path to anything else than a primitive type.

Example

let foo: String = String::new();

Use instead:

let foo = String::new();
Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

ref_as_ptr📋
pedanticallow

What it does

Checks for casts of references to pointer usingasand suggestsstd::ptr::from_ref andstd::ptr::from_mut instead.

Why is this bad?

Usingas casts may result in silently changing mutability or type.

Example

let a_ref = &1;let a_ptr = a_ref as *const _;

Use instead:

let a_ref = &1;let a_ptr = std::ptr::from_ref(a_ref);
Applicability:MachineApplicable(?)
Added in:1.78.0
Related Issues
View Source

ref_binding_to_reference📋
pedanticallow

What it does

Checks forref bindings which create a reference to a reference.

Why is this bad?

The address-of operator at the use site is clearer about the need for a reference.

Example

let x = Some("");if let Some(ref x) = x {    // use `x` here}

Use instead:

let x = Some("");if let Some(x) = x {    // use `&x` here}
Applicability:MachineApplicable(?)
Added in:1.54.0
Related Issues
View Source

ref_option📋
pedanticallow

What it does

Warns when a function signature uses&Option<T> instead ofOption<&T>.

Why is this bad?

More flexibility, better memory optimization, and more idiomatic Rust code.

&Option<T> in a function signature breaks encapsulation because the caller must own Tand move it into an Option to call with it. When returned, the owner must internally storeit asOption<T> in order to return it.At a lower level,&Option<T> points to memory with thepresence bit flag plus theT value,whereasOption<&T> is usuallyoptimizedto a single pointer, so it may be more optimal.

See thisYouTube video byLogan Smith for an in-depth explanation of why this is important.

Known problems

This lint recommends changing the function signatures, but it cannotautomatically change the function calls or the function implementations.

Example

// caller uses  foo(&opt)fn foo(a: &Option<String>) {}fn bar(&self) -> &Option<String> { &None }

Use instead:

// caller should use  `foo1(opt.as_ref())`fn foo1(a: Option<&String>) {}// better yet, use string slice  `foo2(opt.as_deref())`fn foo2(a: Option<&str>) {}fn bar(&self) -> Option<&String> { None }

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:1.83.0
Related Issues
View Source

ref_option_ref📋
pedanticallow

What it does

Checks for usage of&Option<&T>.

Why is this bad?

Since& is Copy, it’s useless to have areference onOption<&T>.

Known problems

It may be irrelevant to use this lint onpublic API code as it will make a breaking change to apply it.

Example

let x: &Option<&u32> = &Some(&0u32);

Use instead:

let x: Option<&u32> = Some(&0u32);
Applicability:MaybeIncorrect(?)
Added in:1.49.0
Related Issues
View Source

ref_patterns📋
restrictionallow

What it does

Checks for usages of theref keyword.

Why restrict this?

Theref keyword can be confusing for people unfamiliar with it, and oftenit is more concise to use& instead.

Example

let opt = Some(5);if let Some(ref foo) = opt {}

Use instead:

let opt = Some(5);if let Some(foo) = &opt {}
Applicability:Unspecified(?)
Added in:1.71.0
Related Issues
View Source

regex_creation_in_loops📋
perfwarn

What it does

Checks forregex compilation inside a loop with a literal.

Why is this bad?

Compiling a regex is a much more expensive operation than using one, and a compiled regex can be used multiple times.This is documented as an antipatternon the regex documentation

Example

for haystack in haystacks {    let regex = regex::Regex::new(MY_REGEX).unwrap();    if regex.is_match(haystack) {        // Perform operation    }}

can be replaced with

let regex = regex::Regex::new(MY_REGEX).unwrap();for haystack in haystacks {    if regex.is_match(haystack) {        // Perform operation    }}
Applicability:Unspecified(?)
Added in:1.84.0
Related Issues
View Source

regex_macro📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

Theregex! macro was removed from the regex crate in 2018.

Applicability:Unspecified(?)
Deprecated in:1.47.0
Related Issues

renamed_function_params📋
restrictionallow

What it does

Lints when the name of function parameters from trait impl isdifferent than its default implementation.

Why restrict this?

Using the default name for parameters of a trait method is more consistent.

Example

struct A(u32);impl PartialEq for A {    fn eq(&self, b: &Self) -> bool {        self.0 == b.0    }}

Use instead:

struct A(u32);impl PartialEq for A {    fn eq(&self, other: &Self) -> bool {        self.0 == other.0    }}

Configuration

  • allow-renamed-params-for: List of trait paths to ignore when checking renamed function parameters.

Example

allow-renamed-params-for = [ "std::convert::From" ]

Noteworthy

  • By default, the following traits are ignored:From,TryFrom,FromStr

  • ".." can be used as part of the list to indicate that the configured values should be appended to thedefault configuration of Clippy. By default, any configuration will replace the default value.

    (default:["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"])

Applicability:Unspecified(?)
Added in:1.80.0
Related Issues
View Source

repeat_once📋
complexitywarn

What it does

Checks for usage of.repeat(1) and suggest the following method for each types.

  • .to_string() forstr
  • .clone() forString
  • .to_vec() forslice

The lint will evaluate constant expressions and values as arguments of.repeat(..) and emit a message ifthey are equivalent to1. (Related discussion inrust-clippy#7306)

Why is this bad?

For example,String.repeat(1) is equivalent to.clone(). If cloningthe string is the intention behind this,clone() should be used.

Example

fn main() {    let x = String::from("hello world").repeat(1);}

Use instead:

fn main() {    let x = String::from("hello world").clone();}
Applicability:MachineApplicable(?)
Added in:1.47.0
Related Issues
View Source

repeat_vec_with_capacity📋
suspiciouswarn

What it does

Looks for patterns such asvec![Vec::with_capacity(x); n] oriter::repeat(Vec::with_capacity(x)).

Why is this bad?

These constructs work by cloning the element, but cloning aVec<_> does notrespect the old vector’s capacity and effectively discards it.

This makesiter::repeat(Vec::with_capacity(x)) especially suspicious because the user most certainlyexpected that the yieldedVec<_> will have the requested capacity, otherwise one can simply writeiter::repeat(Vec::new()) instead and it will have the same effect.

Similarly forvec![x; n], the elementx is cloned to fill the vec.Unlikeiter::repeat however, the vec repeat macro does not have to clone the valuen timesbut justn - 1 times, because it can reuse the passed value for the last slot.That means that the lastVec<_> gets the requested capacity but all other ones do not.

Example

let _: Vec<Vec<u8>> = vec![Vec::with_capacity(42); 123];let _: Vec<Vec<u8>> = iter::repeat(Vec::with_capacity(42)).take(123).collect();

Use instead:

let _: Vec<Vec<u8>> = iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect();//                                      ^^^ this closure executes 123 times//                                          and the vecs will have the expected capacity

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MaybeIncorrect(?)
Added in:1.76.0
Related Issues
View Source

replace_box📋
perfwarn

What it does

Detects assignments ofDefault::default() orBox::new(value)to a place of typeBox<T>.

Why is this bad?

This incurs an extra heap allocation compared to assigning the boxedstorage.

Example

let mut b = Box::new(1u32);b = Default::default();

Use instead:

let mut b = Box::new(1u32);*b = Default::default();
Applicability:MachineApplicable(?)
Added in:1.92.0
Related Issues
View Source

replace_consts📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

min_value andmax_value are now deprecated.

Applicability:Unspecified(?)
Deprecated in:1.44.0
Related Issues

repr_packed_without_abi📋
suspiciouswarn

What it does

Checks for items with#[repr(packed)]-attribute without ABI qualification

Why is this bad?

Without qualification,repr(packed) impliesrepr(Rust). The Rust-ABI is inherently unstable.While this is fine as long as the type is accessed correctly within Rust-code, most usesof#[repr(packed)] involve FFI and/or data structures specified by network-protocols orother external specifications. In such situations, the unstable Rust-ABI implied in#[repr(packed)] may lead to future bugs should the Rust-ABI change.

In case you are relying on a well defined and stable memory layout, qualify the type’srepresentation using theC-ABI. Otherwise, if the type in question is only everaccessed from Rust-code according to Rust’s rules, use theRust-ABI explicitly.

Example

#[repr(packed)]struct NetworkPacketHeader {    header_length: u8,    header_version: u16}

Use instead:

#[repr(C, packed)]struct NetworkPacketHeader {    header_length: u8,    header_version: u16}
Applicability:Unspecified(?)
Added in:1.85.0
Related Issues
View Source

reserve_after_initialization📋
complexitywarn

What it does

Informs the user about a more concise way to create a vector with a known capacity.

Why is this bad?

TheVec::with_capacity constructor is less complex.

Example

let mut v: Vec<usize> = vec![];v.reserve(10);

Use instead:

let mut v: Vec<usize> = Vec::with_capacity(10);
Applicability:HasPlaceholders(?)
Added in:1.74.0
Related Issues
View Source

rest_pat_in_fully_bound_structs📋
restrictionallow

What it does

Checks for unnecessary ‘..’ pattern binding on struct when all fields are explicitly matched.

Why restrict this?

Correctness and readability. It’s like having a wildcard pattern aftermatching all enum variants explicitly.

Example

let a = A { a: 5 };match a {    A { a: 5, .. } => {},    _ => {},}

Use instead:

match a {    A { a: 5 } => {},    _ => {},}
Applicability:MachineApplicable(?)
Added in:1.43.0
Related Issues
View Source

result_filter_map📋
complexitywarn

What it does

Checks for iterators ofResults using.filter(Result::is_ok).map(Result::unwrap) that maybe replaced with a.flatten() call.

Why is this bad?

Result implementsIntoIterator<Item = T>. This means thatResult can be flattenedautomatically without suspicious-lookingunwrap calls.

Example

let _ = std::iter::empty::<Result<i32, ()>>().filter(Result::is_ok).map(Result::unwrap);

Use instead:

let _ = std::iter::empty::<Result<i32, ()>>().flatten();
Applicability:MachineApplicable(?)
Added in:1.77.0
Related Issues
View Source

result_large_err📋
perfwarn

What it does

Checks for functions that returnResult with an unusually largeErr-variant.

Why is this bad?

AResult is at least as large as theErr-variant. While weexpect that variant to be seldom used, the compiler needs to reserveand move that much memory every single time.Furthermore, errors are often simply passed up the call-stack, makinguse of the?-operator and its type-conversion mechanics. If theErr-variant further up the call-stack stores theErr-variant inquestion (as library code often does), it itself needs to be at leastas large, propagating the problem.

Known problems

The size determined by Clippy is platform-dependent.

Examples

pub enum ParseError {    UnparsedBytes([u8; 512]),    UnexpectedEof,}// The `Result` has at least 512 bytes, even in the `Ok`-casepub fn parse() -> Result<(), ParseError> {    Ok(())}

should be

pub enum ParseError {    UnparsedBytes(Box<[u8; 512]>),    UnexpectedEof,}// The `Result` is slightly larger than a pointerpub fn parse() -> Result<(), ParseError> {    Ok(())}

Configuration

  • large-error-threshold: The maximum size of theErr-variant in aResult returned from a function

    (default:128)

Applicability:Unspecified(?)
Added in:1.65.0
Related Issues
View Source

result_map_or_into_option📋
stylewarn

What it does

Checks for usage of_.map_or(None, Some).

Why is this bad?

Readability, this can be written more concisely as_.ok().

Example

assert_eq!(Some(1), r.map_or(None, Some));

Use instead:

assert_eq!(Some(1), r.ok());
Applicability:MachineApplicable(?)
Added in:1.44.0
Related Issues
View Source

result_map_unit_fn📋
complexitywarn

What it does

Checks for usage ofresult.map(f) where f is a functionor closure that returns the unit type().

Why is this bad?

Readability, this can be written more clearly withan if let statement

Example

let x: Result<String, String> = do_stuff();x.map(log_err_msg);x.map(|msg| log_err_msg(format_msg(msg)));

The correct use would be:

let x: Result<String, String> = do_stuff();if let Ok(msg) = x {    log_err_msg(msg);};if let Ok(msg) = x {    log_err_msg(format_msg(msg));};
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

result_unit_err📋
stylewarn

What it does

Checks for public functions that return aResultwith anErr type of(). It suggests using a custom type thatimplementsstd::error::Error.

Why is this bad?

Unit does not implementError and carries nofurther information about what went wrong.

Known problems

Of course, this lint assumes thatResult is usedfor a fallible operation (which is after all the intended use). Howevercode may opt to (mis)use it as a basic two-variant-enum. In that case,the suggestion is misguided, and the code should use a custom enuminstead.

Examples

pub fn read_u8() -> Result<u8, ()> { Err(()) }

should become

use std::fmt;#[derive(Debug)]pub struct EndOfStream;impl fmt::Display for EndOfStream {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        write!(f, "End of Stream")    }}impl std::error::Error for EndOfStream { }pub fn read_u8() -> Result<u8, EndOfStream> { Err(EndOfStream) }

Note that there are crates that simplify creating the error type, e.g.thiserror.

Applicability:Unspecified(?)
Added in:1.49.0
Related Issues
View Source

return_and_then📋
restrictionallow

What it does

Detect functions that end withOption::and_then orResult::and_then, and suggest usingthe? operator instead.

Why is this bad?

Theand_then method is used to chain a computation that returns anOption or aResult.This can be replaced with the? operator, which is more concise and idiomatic.

Example

fn test(opt: Option<i32>) -> Option<i32> {    opt.and_then(|n| {        if n > 1 {            Some(n + 1)        } else {            None       }    })}

Use instead:

fn test(opt: Option<i32>) -> Option<i32> {    let n = opt?;    if n > 1 {        Some(n + 1)    } else {        None    }}
Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

return_self_not_must_use📋
pedanticallow

What it does

This lint warns when a method returningSelf doesn’t have the#[must_use] attribute.

Why is this bad?

Methods returningSelf often create new values, having the#[must_use] attributeprevents users from “forgetting” to use the newly created value.

The#[must_use] attribute can be added to the type itself to ensure that instancesare never forgotten. Functions returning a type marked with#[must_use] will not belinted, as the usage is already enforced by the type attribute.

Limitations

This lint is only applied on methods taking aself argument. It would be mostly noiseif it was added on constructors for example.

Example

pub struct Bar;impl Bar {    // Missing attribute    pub fn bar(&self) -> Self {        Self    }}

Use instead:

// It's better to have the `#[must_use]` attribute on the method like this:pub struct Bar;impl Bar {    #[must_use]    pub fn bar(&self) -> Self {        Self    }}// Or on the type definition like this:#[must_use]pub struct Bar;impl Bar {    pub fn bar(&self) -> Self {        Self    }}
Applicability:Unspecified(?)
Added in:1.59.0
Related Issues
View Source

reversed_empty_ranges📋
correctnessdeny

What it does

Checks for range expressionsx..y where bothx andyare constant andx is greater toy. Also triggers ifx is equal toy when they are conditions to afor loop.

Why is this bad?

Empty ranges yield no values so iterating them is a no-op.Moreover, trying to use a reversed range to index a slice will panic at run-time.

Example

fn main() {    (10..=0).for_each(|x| println!("{}", x));    let arr = [1, 2, 3, 4, 5];    let sub = &arr[3..1];}

Use instead:

fn main() {    (0..=10).rev().for_each(|x| println!("{}", x));    let arr = [1, 2, 3, 4, 5];    let sub = &arr[1..3];}

Past names

  • reverse_range_loop
Applicability:MaybeIncorrect(?)
Added in:1.45.0
Related Issues
View Source

same_functions_in_if_condition📋
pedanticallow

What it does

Checks for consecutiveifs with the same function call.

Why is this bad?

This is probably a copy & paste error.Despite the fact that function can have side effects andif works asintended, such an approach is implicit and can be considered a “code smell”.

Example

if foo() == bar {    …} else if foo() == bar {    …}

This probably should be:

if foo() == bar {    …} else if foo() == baz {    …}

or if the original code was not a typo and called function mutates a state,consider move the mutation out of theif condition to avoid similarity toa copy & paste error:

let first = foo();if first == bar {    …} else {    let second = foo();    if second == bar {    …    }}
Applicability:Unspecified(?)
Added in:1.41.0
Related Issues
View Source

same_item_push📋
stylewarn

What it does

Checks whether a for loop is being used to push a constantvalue into a Vec.

Why is this bad?

This kind of operation can be expressed more succinctly withvec![item; SIZE] orvec.resize(NEW_SIZE, item) and using these alternatives may alsohave better performance.

Example

let item1 = 2;let item2 = 3;let mut vec: Vec<u8> = Vec::new();for _ in 0..20 {    vec.push(item1);}for _ in 0..30 {    vec.push(item2);}

Use instead:

let item1 = 2;let item2 = 3;let mut vec: Vec<u8> = vec![item1; 20];vec.resize(20 + 30, item2);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:Unspecified(?)
Added in:1.47.0
Related Issues
View Source

same_name_method📋
restrictionallow

What it does

It lints if a struct has two methods with the same name:one from a trait, another not from a trait.

Why restrict this?

Confusing.

Example

trait T {    fn foo(&self) {}}struct S;impl T for S {    fn foo(&self) {}}impl S {    fn foo(&self) {}}
Applicability:Unspecified(?)
Added in:1.57.0
Related Issues
View Source

search_is_some📋
complexitywarn

What it does

Checks for an iterator or string search (such asfind(),position(), orrposition()) followed by a call tois_some() oris_none().

Why is this bad?

Readability, this can be written more concisely as:

  • _.any(_), or_.contains(_) foris_some(),
  • !_.any(_), or!_.contains(_) foris_none().

Example

let vec = vec![1];vec.iter().find(|x| **x == 0).is_some();"hello world".find("world").is_none();

Use instead:

let vec = vec![1];vec.iter().any(|x| *x == 0);!"hello world".contains("world");
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

seek_from_current📋
complexitywarn

What it does

Checks if theseek method of theSeek trait is called withSeekFrom::Current(0),and if it is, suggests usingstream_position instead.

Why is this bad?

Readability. Use dedicated method.

Example

use std::fs::File;use std::io::{self, Write, Seek, SeekFrom};fn main() -> io::Result<()> {    let mut f = File::create("foo.txt")?;    f.write_all(b"Hello")?;    eprintln!("Written {} bytes", f.seek(SeekFrom::Current(0))?);    Ok(())}

Use instead:

use std::fs::File;use std::io::{self, Write, Seek, SeekFrom};fn main() -> io::Result<()> {    let mut f = File::create("foo.txt")?;    f.write_all(b"Hello")?;    eprintln!("Written {} bytes", f.stream_position()?);    Ok(())}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.67.0
Related Issues
View Source

seek_to_start_instead_of_rewind📋
complexitywarn

What it does

Checks for jumps to the start of a stream that implementsSeekand uses theseek method providingStart as parameter.

Why is this bad?

Readability. There is a specific method that was implemented forthis exact scenario.

Example

fn foo<T: io::Seek>(t: &mut T) {    t.seek(io::SeekFrom::Start(0));}

Use instead:

fn foo<T: io::Seek>(t: &mut T) {    t.rewind();}
Applicability:MachineApplicable(?)
Added in:1.67.0
Related Issues
View Source

self_assignment📋
correctnessdeny

What it does

Checks for explicit self-assignments.

Why is this bad?

Self-assignments are redundant and unlikely to beintentional.

Known problems

If expression contains any deref coercions orindexing operations they are assumed not to have any side effects.

Example

struct Event {    x: i32,}fn copy_position(a: &mut Event, b: &Event) {    a.x = a.x;}

Should be:

struct Event {    x: i32,}fn copy_position(a: &mut Event, b: &Event) {    a.x = b.x;}
Applicability:Unspecified(?)
Added in:1.48.0
Related Issues
View Source

self_named_constructors📋
stylewarn

What it does

Warns when constructors have the same name as their types.

Why is this bad?

Repeating the name of the type is redundant.

Example

struct Foo {}impl Foo {    pub fn foo() -> Foo {        Foo {}    }}

Use instead:

struct Foo {}impl Foo {    pub fn new() -> Foo {        Foo {}    }}
Applicability:Unspecified(?)
Added in:1.55.0
Related Issues
View Source

self_named_module_files📋
restrictionallow

What it does

Checks that module layout uses onlymod.rs files.

Why restrict this?

Having multiple module layout styles in a project can be confusing.

Example

src/  stuff/    stuff_files.rs  stuff.rs  lib.rs

Use instead:

src/  stuff/    stuff_files.rs    mod.rs  lib.rs
Applicability:Unspecified(?)
Added in:1.57.0
Related Issues
View Source

self_only_used_in_recursion📋
pedanticallow

What it does

Checks forself receiver that is only used in recursion with no side-effects.

Why is this bad?

It may be possible to remove theself argument, allowing the function to beused without an object of typeSelf.

Example

struct Foo;impl Foo {    fn f(&self, n: u32) -> u32 {        if n == 0 {            1        } else {            n * self.f(n - 1)        }    }}

Use instead:

struct Foo;impl Foo {    fn f(n: u32) -> u32 {        if n == 0 {            1        } else {            n * Self::f(n - 1)        }    }}

Known problems

Too many code paths in the linting code are currently untested and prone to produce falsepositives or are prone to have performance implications.

In some cases, this would not catch all useless arguments.

struct Foo;impl Foo {    fn foo(&self, a: usize) -> usize {        let f = |x| x;        if a == 0 {            1        } else {            f(self).foo(a)        }    }}

For example, hereself is only used in recursion, but the lint would not catch it.

List of some examples that can not be caught:

  • binary operation of non-primitive types
  • closure usage
  • somebreak relative operations
  • struct pattern binding

Also, when you recurse the function name with path segments, it is not possible to detect.

Applicability:Unspecified(?)
Added in:1.92.0
Related Issues
View Source

semicolon_if_nothing_returned📋
pedanticallow

What it does

Looks for blocks of expressions and fires if the last expression returns() but is not followed by a semicolon.

Why is this bad?

The semicolon might be optional but when extending the block with newcode, it doesn’t require a change in previous last line.

Example

fn main() {    println!("Hello world")}

Use instead:

fn main() {    println!("Hello world");}
Applicability:MachineApplicable(?)
Added in:1.52.0
Related Issues
View Source

semicolon_inside_block📋
restrictionallow

What it does

Suggests moving the semicolon after a block to the inside of the block, after its lastexpression.

Why restrict this?

For consistency it’s best to have the semicolon inside/outside the block. Either way is fineand this lint suggests inside the block.Take a look atsemicolon_outside_block for the other alternative.

Example

unsafe { f(x) };

Use instead:

unsafe { f(x); }

Configuration

  • semicolon-inside-block-ignore-singleline: Whether to lint only if it’s multiline.

    (default:false)

Applicability:MachineApplicable(?)
Added in:1.68.0
Related Issues
View Source

semicolon_outside_block📋
restrictionallow

What it does

Suggests moving the semicolon from a block’s final expression outside of the block.

Why restrict this?

For consistency it’s best to have the semicolon inside/outside the block. Either way is fineand this lint suggests outside the block.Take a look atsemicolon_inside_block for the other alternative.

Example

unsafe { f(x); }

Use instead:

unsafe { f(x) };

Configuration

  • semicolon-outside-block-ignore-multiline: Whether to lint only if it’s singleline.

    (default:false)

Applicability:MachineApplicable(?)
Added in:1.68.0
Related Issues
View Source

separated_literal_suffix📋
restrictionallow

What it does

Warns if literal suffixes are separated by an underscore.To enforce separated literal suffix style,see theunseparated_literal_suffix lint.

Why restrict this?

Suffix style should be consistent.

Example

123832_i32

Use instead:

123832i32
Applicability:MachineApplicable(?)
Added in:1.58.0
Related Issues
View Source

serde_api_misuse📋
correctnessdeny

What it does

Checks for misuses of the serde API.

Why is this bad?

Serde is very finicky about how its API should beused, but the type system can’t be used to enforce it (yet?).

Example

ImplementingVisitor::visit_string but notVisitor::visit_str.

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

set_contains_or_insert📋
nurseryallow

What it does

Checks for usage ofcontains to see if a value is not presentin a set likeHashSet orBTreeSet, followed by aninsert.

Why is this bad?

Using justinsert and checking the returnedbool is more efficient.

Known problems

In case the value that wants to be inserted is borrowed and also expensive or impossibleto clone. In such a scenario, the developer might want to check withcontains before inserting,to avoid the clone. In this case, it will report a false positive.

Example

use std::collections::HashSet;let mut set = HashSet::new();let value = 5;if !set.contains(&value) {    set.insert(value);    println!("inserted {value:?}");}

Use instead:

use std::collections::HashSet;let mut set = HashSet::new();let value = 5;if set.insert(&value) {    println!("inserted {value:?}");}
Applicability:Unspecified(?)
Added in:1.81.0
Related Issues
View Source

shadow_reuse📋
restrictionallow

What it does

Checks for bindings that shadow other bindings already inscope, while reusing the original value.

Why restrict this?

Some argue that name shadowing like this hurts readability,because a value may be bound to different things depending on position inthe code.

See alsoshadow_same andshadow_unrelated for other restrictions on shadowing.

Example

let x = 2;let x = x + 1;

use different variable name:

let x = 2;let y = x + 1;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

shadow_same📋
restrictionallow

What it does

Checks for bindings that shadow other bindings already inscope, while just changing reference level or mutability.

Why restrict this?

To require that what are formally distinct variables be given distinct names.

See alsoshadow_reuse andshadow_unrelated for other restrictions on shadowing.

Example

let x = &x;

Use instead:

let y = &x; // use different variable name
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

shadow_unrelated📋
restrictionallow

What it does

Checks for bindings that shadow other bindings already inscope, either without an initialization or with one that does not even usethe original value.

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 inlarge code bases, because it is easy to lose track of the active binding atany place in the code. If linting against all shadowing is desired, you may wishto use theshadow_same andshadow_reuse lints as well.

Example

let x = y;let x = z; // shadows the earlier binding

Use instead:

let x = y;let w = z; // use different variable name
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

short_circuit_statement📋
complexitywarn

What it does

Checks for the use of short circuit boolean conditions asastatement.

Why is this bad?

Using a short circuit boolean condition as a statementmay hide the fact that the second part is executed or not depending on theoutcome of the first part.

Example

f() && g(); // We should write `if f() { g(); }`.
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

should_assert_eq📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

assert!(a == b) can now print the values the same way `assert_eq!(a, b) can.

Applicability:Unspecified(?)
Deprecated in:pre 1.29.0
Related Issues

should_implement_trait📋
stylewarn

What it does

Checks for methods that should live in a traitimplementation of astd trait (seellogiq’s blogpost for furtherinformation) instead of an inherent implementation.

Why is this bad?

Implementing the traits improve ergonomics for users ofthe code, often with very little cost. Also people seeing amul(...)methodmay expect* to work equally, so you should have good reason to disappointthem.

Example

struct X;impl X {    fn add(&self, other: &X) -> X {        // ..    }}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

should_panic_without_expect📋
pedanticallow

What it does

Checks for#[should_panic] attributes without specifying the expected panic message.

Why is this bad?

The expected panic message should be specified to ensure that the test is actuallypanicking with the expected message, and not another unrelated panic.

Example

fn random() -> i32 { 0 }#[should_panic]#[test]fn my_test() {    let _ = 1 / random();}

Use instead:

fn random() -> i32 { 0 }#[should_panic = "attempt to divide by zero"]#[test]fn my_test() {    let _ = 1 / random();}
Applicability:HasPlaceholders(?)
Added in:1.74.0
Related Issues
View Source

significant_drop_in_scrutinee📋
nurseryallow

What it does

Checks for temporaries returned from function calls in a match scrutinee that have theclippy::has_significant_drop attribute.

Why is this bad?

Theclippy::has_significant_drop attribute can be added to types whose Drop impls havean important side-effect, such as unlocking a mutex, making it important for users to beable to accurately understand their lifetimes. When a temporary is returned in a functioncall in a match scrutinee, its lifetime lasts until the end of the match block, which maybe surprising.

ForMutexes this can lead to a deadlock. This happens when the match scrutinee uses afunction call that returns aMutexGuard and then tries to lock again in one of the matcharms. In that case theMutexGuard in the scrutinee will not be dropped until the end ofthe match block and thus will not unlock.

Example

let mutex = Mutex::new(State {});match mutex.lock().unwrap().foo() {    true => {        mutex.lock().unwrap().bar(); // Deadlock!    }    false => {}};println!("All done!");

Use instead:

let mutex = Mutex::new(State {});let is_foo = mutex.lock().unwrap().foo();match is_foo {    true => {        mutex.lock().unwrap().bar();    }    false => {}};println!("All done!");
Applicability:MaybeIncorrect(?)
Added in:1.60.0
Related Issues
View Source

significant_drop_tightening📋
nurseryallow

What it does

Searches for elements marked with#[clippy::has_significant_drop] that could be earlydropped but are in fact dropped at the end of their scopes. In other words, enforces the“tightening” of their possible lifetimes.

Why is this bad?

Elements marked with#[clippy::has_significant_drop] are generally synchronizingprimitives that manage shared resources, as such, it is desired to release them as soon aspossible to avoid unnecessary resource contention.

Example

fn main() {  let lock = some_sync_resource.lock();  let owned_rslt = lock.do_stuff_with_resource();  // Only `owned_rslt` is needed but `lock` is still held.  do_heavy_computation_that_takes_time(owned_rslt);}

Use instead:

fn main() {    let owned_rslt = some_sync_resource.lock().do_stuff_with_resource();    do_heavy_computation_that_takes_time(owned_rslt);}
Applicability:MaybeIncorrect(?)
Added in:1.69.0
Related Issues
View Source

similar_names📋
pedanticallow

What it does

Checks for names that are very similar and thus confusing.

Note: this lint looks for similar names throughout eachscope. To allow it, you need to allow it on the scopelevel, not on the name that is reported.

Why is this bad?

It’s hard to distinguish between names that differ onlyby a single character.

Example

let checked_exp = something;let checked_expr = something_else;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

single_call_fn📋
restrictionallow

What it does

Checks for functions that are only used once. Does not lint tests.

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.

However, there are reasons not to do this everywhere:

  • Splitting a large function into multiple parts often improves readabilityby giving names to its parts.
  • A function’s signature might serve a necessary purpose, such as constrainingthe type of a closure passed to it.
  • Generic functions might call non-generic functions to reduce duplicationin the produced machine code.

If this lint is used, prepare to#[allow] it a lot.

Example

pub fn a<T>(t: &T)where    T: AsRef<str>,{    a_inner(t.as_ref())}fn a_inner(t: &str) {    /* snip */}

Use instead:

pub fn a<T>(t: &T)where    T: AsRef<str>,{    let t = t.as_ref();    /* snip */}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

single_char_add_str📋
stylewarn

What it does

Warns when usingpush_str/insert_str with a single-character string literalwherepush/insert with achar would work fine.

Why is this bad?

It’s less clear that we are pushing a single character.

Example

string.insert_str(0, "R");string.push_str("R");

Use instead:

string.insert(0, 'R');string.push('R');

Past names

  • single_char_push_str
Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

single_char_lifetime_names📋
restrictionallow

What it does

Checks for lifetimes with names which are one characterlong.

Why restrict this?

A single character is likely not enough to express thepurpose of a lifetime. Using a longer name can make codeeasier to understand.

Known problems

Rust programmers and learning resources tend to use singlecharacter lifetimes, so this lint is at odds with theecosystem at large. In addition, the lifetime’s purpose maybe obvious or, rarely, expressible in one character.

Example

struct DiagnosticCtx<'a> {    source: &'a str,}

Use instead:

struct DiagnosticCtx<'src> {    source: &'src str,}
Applicability:Unspecified(?)
Added in:1.60.0
Related Issues
View Source

single_char_pattern📋
pedanticallow

What it does

Checks for string methods that receive a single-characterstr as an argument, e.g.,_.split("x").

Why is this bad?

While this can make a perf difference on some systems,benchmarks have proven inconclusive. But at least using achar literal makes it clear that we are looking at a singlecharacter.

Known problems

Does not catch multi-byte unicode characters. This is bydesign, on many machines, splitting by a non-ascii char isactually slower. Please do your own measurements instead ofrelying solely on the results of this lint.

Example

_.split("x");

Use instead:

_.split('x');
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

single_component_path_imports📋
stylewarn

What it does

Checking for imports with single component use path.

Why is this bad?

Import with single component use path such asuse cratename;is not necessary, and thus should be removed.

Example

use regex;fn main() {    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();}

Better as

fn main() {    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();}
Applicability:MachineApplicable(?)
Added in:1.43.0
Related Issues
View Source

single_element_loop📋
complexitywarn

What it does

Checks whether a for loop has a single element.

Why is this bad?

There is no reason to have a loop of asingle element.

Example

let item1 = 2;for item in &[item1] {    println!("{}", item);}

Use instead:

let item1 = 2;let item = &item1;println!("{}", item);
Applicability:MachineApplicable(?)
Added in:1.49.0
Related Issues
View Source

single_match📋
stylewarn

What it does

Checks for matches with a single arm where anif letwill usually suffice.

This intentionally does not lint if there are commentsinside of the other arm, so as to allow the user to documentwhy having another explicit pattern with an empty body is necessary,or because the comments need to be preserved for other reasons.

Why is this bad?

Just readability –if let nests less than amatch.

Example

match x {    Some(ref foo) => bar(foo),    _ => (),}

Use instead:

if let Some(ref foo) = x {    bar(foo);}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

single_match_else📋
pedanticallow

What it does

Checks for matches with two arms where anif let else willusually suffice.

Why is this bad?

Just readability –if let nests less than amatch.

Known problems

Personal style preferences may differ.

Example

Usingmatch:

match x {    Some(ref foo) => bar(foo),    _ => bar(&other_ref),}

Usingif let withelse:

if let Some(ref foo) = x {    bar(foo);} else {    bar(&other_ref);}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

single_option_map📋
nurseryallow

What it does

Checks for functions with method calls to.map(_) on an argof typeOption as the outermost expression.

Why is this bad?

Taking and returning anOption<T> may require additionalSome(_) andunwrap if all you have is aT.

Example

fn double(param: Option<u32>) -> Option<u32> {    param.map(|x| x * 2)}

Use instead:

fn double(param: u32) -> u32 {    param * 2}
Applicability:Unspecified(?)
Added in:1.87.0
Related Issues
View Source

single_range_in_vec_init📋
suspiciouswarn

What it does

Checks forVec or array initializations that contain only one range.

Why is this bad?

This is almost always incorrect, as it will result in aVec that has only one element.Almost always, the programmer intended for it to include all elements in the range or forthe end of the range to be the length instead.

Example

let x = [0..200];

Use instead:

// If it was intended to include every element in the range...let x = (0..200).collect::<Vec<i32>>();// ...Or if 200 was meant to be the lenlet x = [0; 200];
Applicability:MaybeIncorrect(?)
Added in:1.72.0
Related Issues
View Source

size_of_in_element_count📋
correctnessdeny

What it does

Detects expressions wheresize_of::<T> orsize_of_val::<T> is used as acount of elements of typeT

Why is this bad?

These functions expect a countofT and not a number of bytes

Example

const SIZE: usize = 128;let x = [2u8; SIZE];let mut y = [2u8; SIZE];unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
Applicability:Unspecified(?)
Added in:1.50.0
Related Issues
View Source

size_of_ref📋
suspiciouswarn

What it does

Checks for calls tosize_of_val() where the argument isa reference to a reference.

Why is this bad?

Callingsize_of_val() with a reference to a reference as the argumentyields the size of the reference-type, not the size of the value behindthe reference.

Example

struct Foo {    buffer: [u8],}impl Foo {    fn size(&self) -> usize {        // Note that `&self` as an argument is a `&&Foo`: Because `self`        // is already a reference, `&self` is a double-reference.        // The return value of `size_of_val()` therefore is the        // size of the reference-type, not the size of `self`.        size_of_val(&self)    }}

Use instead:

struct Foo {    buffer: [u8],}impl Foo {    fn size(&self) -> usize {        // Correct        size_of_val(self)    }}
Applicability:Unspecified(?)
Added in:1.68.0
Related Issues
View Source

skip_while_next📋
complexitywarn

What it does

Checks for usage of_.skip_while(condition).next().

Why is this bad?

Readability, this can be written more concisely as_.find(!condition).

Example

vec.iter().skip_while(|x| **x == 0).next();

Use instead:

vec.iter().find(|x| **x != 0);
Applicability:Unspecified(?)
Added in:1.42.0
Related Issues
View Source

sliced_string_as_bytes📋
perfwarn

What it does

Checks for string slices immediately followed byas_bytes.

Why is this bad?

It involves doing an unnecessary UTF-8 alignment check which is less efficient, and can cause a panic.

Known problems

In some cases, the UTF-8 validation and potential panic from string slicing may be required forthe code’s correctness. If you need to ensure the slice boundaries fall on valid UTF-8 characterboundaries, the original form (s[1..5].as_bytes()) should be preferred.

Example

let s = "Lorem ipsum";s[1..5].as_bytes();

Use instead:

let s = "Lorem ipsum";&s.as_bytes()[1..5];
Applicability:MaybeIncorrect(?)
Added in:1.86.0
Related Issues
View Source

slow_vector_initialization📋
perfwarn

What it does

Checks slow zero-filled vector initialization

Why is this bad?

These structures are non-idiomatic and less efficient than simply usingvec![0; len].

Specifically, forvec![0; len], the compiler can use a specialized type of allocationthat also zero-initializes the allocated memory in the same call(see:alloc_zeroed).

WritingVec::new() followed byvec.resize(len, 0) is suboptimal because,while it does do the same number of allocations,it involves two operations for allocating and initializing.Theresize call first allocates memory (sinceVec::new() did not), and onlythen zero-initializes it.

Example

let mut vec1 = Vec::new();vec1.resize(len, 0);let mut vec2 = Vec::with_capacity(len);vec2.resize(len, 0);let mut vec3 = Vec::with_capacity(len);vec3.extend(repeat(0).take(len));

Use instead:

let mut vec1 = vec![0; len];let mut vec2 = vec![0; len];let mut vec3 = vec![0; len];
Applicability:Unspecified(?)
Added in:1.32.0
Related Issues
View Source

stable_sort_primitive📋
pedanticallow

What it does

When sorting primitive values (integers, bools, chars, as wellas arrays, slices, and tuples of such items), it is typically better touse an unstable sort than a stable sort.

Why is this bad?

Typically, using a stable sort consumes more memory and cpu cycles.Because values which compare equal are identical, preserving theirrelative order (the guarantee that a stable sort provides) meansnothing, while the extra costs still apply.

Known problems

As pointed out inissue #8241,a stable sort can instead be significantly faster for certain scenarios(eg. when a sorted vector is extended with new data and resorted).

For more information and benchmarking results, please refer to theissue linked above.

Example

let mut vec = vec![2, 1, 3];vec.sort();

Use instead:

let mut vec = vec![2, 1, 3];vec.sort_unstable();
Applicability:MachineApplicable(?)
Added in:1.47.0
Related Issues
View Source

std_instead_of_alloc📋
restrictionallow

What it does

Finds items imported throughstd when available throughalloc.

Why restrict this?

Crates which haveno_std compatibility and require alloc may wish to ensure types are imported fromalloc to ensure disablingstd does not cause the crate to fail to compile. This lint is also usefulfor crates migrating to becomeno_std compatible.

Example

use std::vec::Vec;

Use instead:

use alloc::vec::Vec;
Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

std_instead_of_core📋
restrictionallow

What it does

Finds items imported throughstd when available throughcore.

Why restrict this?

Crates which haveno_std compatibility may wish to ensure types are imported from core to ensuredisablingstd does not cause the crate to fail to compile. This lint is also useful for cratesmigrating to becomeno_std compatible.

Example

use std::hash::Hasher;

Use instead:

use core::hash::Hasher;
Applicability:MachineApplicable(?)
Added in:1.64.0
Related Issues
View Source

str_split_at_newline📋
pedanticallow

What it does

Checks for usages ofstr.trim().split("\n") andstr.trim().split("\r\n").

Why is this bad?

Hard-coding the line endings makes the code less compatible.str.lines should be used instead.

Example

"some\ntext\nwith\nnewlines\n".trim().split('\n');

Use instead:

"some\ntext\nwith\nnewlines\n".lines();

Known Problems

This lint cannot detect if the split is intentionally restricted to a single type of newline ("\n" or"\r\n"), for example during the parsing of a specific file format in which precisely one newline type isvalid.

Applicability:MaybeIncorrect(?)
Added in:1.77.0
Related Issues
View Source

str_to_string📋
restrictionallow

What it does

This lint checks for.to_string() method calls on values of type&str.

Why restrict this?

Theto_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 variantString, which can bemore specifically expressed with.to_owned().

Example

let _ = "str".to_string();

Use instead:

let _ = "str".to_owned();
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

string_add📋
restrictionallow

What it does

Checks for all instances ofx + _ wherex is of typeString, but only ifstring_add_assign doesnotmatch.

Why restrict this?

This particularAdd implementation is asymmetric (the other operand need not beString,butx does), while addition as mathematically defined is symmetric, andtheString::push_str(_) function is a perfectly good replacement.Therefore, some dislike it and wish not to have it in their code.

That said, other people think that string addition, having a long traditionin other languages is actually fine, which is why we decided to make thisparticular lintallow by default.

Example

let x = "Hello".to_owned();x + ", World";

Use instead:

let mut x = "Hello".to_owned();x.push_str(", World");
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

string_add_assign📋
pedanticallow

What it does

Checks for string appends of the formx = x + y (withoutlet!).

Why is this bad?

It’s not really bad, but some people think that the.push_str(_) method is more readable.

Example

let mut x = "Hello".to_owned();x = x + ", World";// More readablex += ", World";x.push_str(", World");
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

string_extend_chars📋
stylewarn

What it does

Checks for the use of.extend(s.chars()) where s is a&str orString.

Why is this bad?

.push_str(s) is clearer

Example

let abc = "abc";let def = String::from("def");let mut s = String::new();s.extend(abc.chars());s.extend(def.chars());

The correct use would be:

let abc = "abc";let def = String::from("def");let mut s = String::new();s.push_str(abc);s.push_str(&def);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

string_from_utf8_as_bytes📋
complexitywarn

What it does

Check if the string is transformed to byte array and casted back to string.

Why is this bad?

It’s unnecessary, the string can be used directly.

Example

std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();

Use instead:

&"Hello World!"[6..11];
Applicability:MachineApplicable(?)
Added in:1.50.0
Related Issues
View Source

string_lit_as_bytes📋
nurseryallow

What it does

Checks for theas_bytes method called on string literalsthat contain only ASCII characters.

Why is this bad?

Byte string literals (e.g.,b"foo") can be usedinstead. They are shorter but less discoverable thanas_bytes().

Known problems

"str".as_bytes() and the suggested replacement ofb"str" are notequivalent because they have different types. The former is&[u8]while the latter is&[u8; 3]. That means in general they will have adifferent set of methods and different trait implementations.

fn f(v: Vec<u8>) {}f("...".as_bytes().to_owned()); // worksf(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>fn g(r: impl std::io::Read) {}g("...".as_bytes()); // worksg(b"..."); // does not work

The actual equivalent of"str".as_bytes() with the same type is notb"str" but&b"str"[..], which is a great deal of punctuation and notmore readable than a function call.

Example

let bstr = "a byte string".as_bytes();

Use instead:

let bstr = b"a byte string";
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

string_lit_chars_any📋
restrictionallow

What it does

Checks for<string_lit>.chars().any(|i| i == c).

Why is this bad?

It’s significantly slower than using a pattern instead, likematches!(c, '\\' | '.' | '+').

Despite this being faster, this is notperf as this is pretty common, and is a rather niceway to check if achar is any in a set. In any case, thisrestriction lint is availablefor situations where that additional performance is absolutely necessary.

Example

"\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);

Use instead:

matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
Applicability:MachineApplicable(?)
Added in:1.73.0
Related Issues
View Source

string_slice📋
restrictionallow

What it does

Checks for slice operations on strings

Why restrict this?

UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse charactercounts and string indices. This may lead to panics, and should warrant some test casescontaining wide UTF-8 characters. This lint is most useful in code that should avoidpanics at all costs.

Known problems

Probably lots of false positives. If an index comes from a known valid position (e.g.obtained viachar_indices over the same string), it is totally OK.

Example

&"Ölkanne"[1..];
Applicability:Unspecified(?)
Added in:1.58.0
Related Issues
View Source

string_to_string📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

clippy:implicit_clone covers those cases.

Applicability:Unspecified(?)
Deprecated in:1.91.0
Related Issues

strlen_on_c_strings📋
complexitywarn

What it does

Checks for usage oflibc::strlen on aCString orCStr value,and suggest callingas_bytes().len() orto_bytes().len() respectively instead.

Why is this bad?

This avoids calling an unsafelibc function.Currently, it also avoids calculating the length.

Example

use std::ffi::CString;let cstring = CString::new("foo").expect("CString::new failed");let len = unsafe { libc::strlen(cstring.as_ptr()) };

Use instead:

use std::ffi::CString;let cstring = CString::new("foo").expect("CString::new failed");let len = cstring.as_bytes().len();
Applicability:MachineApplicable(?)
Added in:1.55.0
Related Issues
View Source

struct_excessive_bools📋
pedanticallow

What it does

Checks for excessiveuse of bools in structs.

Why is this bad?

Excessive bools in a struct is often a sign thatthe type is being used to represent a statemachine, which is much better implemented as anenum.

The reason an enum is better for state machinesover structs is that enums more easily forbidinvalid states.

Structs with too many booleans may benefit from refactoringinto multi variant enums for better readability and API.

Example

struct S {    is_pending: bool,    is_processing: bool,    is_finished: bool,}

Use instead:

enum S {    Pending,    Processing,    Finished,}

Configuration

  • max-struct-bools: The maximum number of bool fields a struct can have

    (default:3)

Applicability:Unspecified(?)
Added in:1.43.0
Related Issues
View Source

struct_field_names📋
pedanticallow

What it does

Detects struct fields that are prefixed or suffixedby the same characters or the name of the struct itself.

Why is this bad?

Information common to all struct fields is better represented in the struct name.

Limitations

Characters with no casing will be considered when comparing prefixes/suffixesThis applies to numbers and non-ascii characters without casinge.g.foo1 andfoo2 is considered to have different prefixes(the prefixes arefoo1 andfoo2 respectively), as alsobar螃,bar蟹

Example

struct Cake {    cake_sugar: u8,    cake_flour: u8,    cake_eggs: u8}

Use instead:

struct Cake {    sugar: u8,    flour: u8,    eggs: u8}

Configuration

  • struct-field-name-threshold: The minimum number of struct fields for the lints about field names to trigger

    (default:3)

Applicability:Unspecified(?)
Added in:1.75.0
Related Issues
View Source

suboptimal_flops📋
nurseryallow

What it does

Looks for floating-point expressions thatcan be expressed using built-in methods to improve bothaccuracy and performance.

Why is this bad?

Negatively impacts accuracy and performance.

Example

use std::f32::consts::E;let a = 3f32;let _ = (2f32).powf(a);let _ = E.powf(a);let _ = a.powf(1.0 / 2.0);let _ = a.log(2.0);let _ = a.log(10.0);let _ = a.log(E);let _ = a.powf(2.0);let _ = a * 2.0 + 4.0;let _ = if a < 0.0 {    -a} else {    a};let _ = if a < 0.0 {    a} else {    -a};

is better expressed as

use std::f32::consts::E;let a = 3f32;let _ = a.exp2();let _ = a.exp();let _ = a.sqrt();let _ = a.log2();let _ = a.log10();let _ = a.ln();let _ = a.powi(2);let _ = a.mul_add(2.0, 4.0);let _ = a.abs();let _ = -a.abs();
Applicability:MachineApplicable(?)
Added in:1.43.0
Related Issues
View Source

suspicious_arithmetic_impl📋
suspiciouswarn

What it does

Lints for suspicious operations in impls of arithmetic operators, e.g.subtracting elements in an Add impl.

Why is this bad?

This is probably a typo or copy-and-paste error and not intended.

Example

impl Add for Foo {    type Output = Foo;    fn add(self, other: Foo) -> Foo {        Foo(self.0 - other.0)    }}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

suspicious_assignment_formatting📋
suspiciouswarn

What it does

Checks for usage of the non-existent=*,=! and=-operators.

Why is this bad?

This is either a typo of*=,!= or-= orconfusing.

Example

a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

suspicious_command_arg_space📋
suspiciouswarn

What it does

Checks forCommand::arg() invocations that look like theyshould be multiple arguments instead, such asarg("-t ext2").

Why is this bad?

Command::arg() does not split arguments by space. An argument likearg("-t ext2")will be passed as a single argument to the command,which is likely not what was intended.

Example

std::process::Command::new("echo").arg("-n hello").spawn().unwrap();

Use instead:

std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
Applicability:MaybeIncorrect(?)
Added in:1.69.0
Related Issues
View Source

suspicious_doc_comments📋
suspiciouswarn

What it does

Detects the use of outer doc comments (///,/**) followed by a bang (!):///!

Why is this bad?

Triple-slash comments (known as “outer doc comments”) apply to items that follow it.An outer doc comment followed by a bang (i.e.///!) has no specific meaning.

The user most likely meant to write an inner doc comment (//!,/*!), whichapplies to the parent item (i.e. the item that the comment is contained in,usually a module or crate).

Known problems

Inner doc comments can only appear before items, so there are certain cases where the suggestionmade by this lint is not valid code. For example:

fn foo() {}///!fn bar() {}

This lint detects the doc comment and suggests changing it to//!, but an inner doc commentis not valid at that position.

Example

In this example, the doc comment is attached to thefunction, rather than themodule.

pub mod util {    ///! This module contains utility functions.    pub fn dummy() {}}

Use instead:

pub mod util {    //! This module contains utility functions.    pub fn dummy() {}}
Applicability:MaybeIncorrect(?)
Added in:1.70.0
Related Issues
View Source

suspicious_else_formatting📋
suspiciouswarn

What it does

Checks for formatting ofelse. It lints if theelseis followed immediately by a newline or theelse seems to be missing.

Why is this bad?

This is probably some refactoring remnant, even if thecode is correct, it might look confusing.

Example

if foo {} { // looks like an `else` is missing here}if foo {} if bar { // looks like an `else` is missing here}if foo {} else{ // this is the `else` block of the previous `if`, but should it be?}if foo {} elseif bar { // this is the `else` block of the previous `if`, but should it be?}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

suspicious_map📋
suspiciouswarn

What it does

Checks for calls tomap followed by acount.

Why is this bad?

It looks suspicious. Maybemap was confused withfilter.If themap call is intentional, this should be rewrittenusinginspect. Or, if you intend to drive the iterator tocompletion, you can just usefor_each instead.

Example

let _ = (0..3).map(|x| x + 2).count();
Applicability:Unspecified(?)
Added in:1.39.0
Related Issues
View Source

suspicious_op_assign_impl📋
suspiciouswarn

What it does

Lints for suspicious operations in impls of OpAssign, e.g.subtracting elements in an AddAssign impl.

Why is this bad?

This is probably a typo or copy-and-paste error and not intended.

Example

impl AddAssign for Foo {    fn add_assign(&mut self, other: Foo) {        *self = *self - other;    }}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

suspicious_open_options📋
suspiciouswarn

What it does

Checks for the suspicious use ofOpenOptions::create()without an explicitOpenOptions::truncate().

Why is this bad?

create() alone will either create a new file or open anexisting file. If the file already exists, it will beoverwritten when written to, but the file will not betruncated by default.If less data is written to the filethan it already contains, the remainder of the file willremain unchanged, and the end of the file will contain olddata.In most cases, one should either usecreate_new to ensurethe file is created from scratch, or ensuretruncate iscalled so that the truncation behaviour is explicit.truncate(true)will ensure the file is entirely overwritten with new data, whereastruncate(false) will explicitly keep the default behavior.

Example

use std::fs::OpenOptions;OpenOptions::new().create(true);

Use instead:

use std::fs::OpenOptions;OpenOptions::new().create(true).truncate(true);
Applicability:MaybeIncorrect(?)
Added in:1.77.0
Related Issues
View Source

suspicious_operation_groupings📋
nurseryallow

What it does

Checks for unlikely usages of binary operators that are almostcertainly typos and/or copy/paste errors, given the other usagesof binary operators nearby.

Why is this bad?

They are probably bugs and if they aren’t then they look like bugsand you should add a comment explaining why you are doing such anodd set of operations.

Known problems

There may be some false positives if you are trying to do somethingunusual that happens to look like a typo.

Example

struct Vec3 {    x: f64,    y: f64,    z: f64,}impl Eq for Vec3 {}impl PartialEq for Vec3 {    fn eq(&self, other: &Self) -> bool {        // This should trigger the lint because `self.x` is compared to `other.y`        self.x == other.y && self.y == other.y && self.z == other.z    }}

Use instead:

// same as above except:impl PartialEq for Vec3 {    fn eq(&self, other: &Self) -> bool {        // Note we now compare other.x to self.x        self.x == other.x && self.y == other.y && self.z == other.z    }}
Applicability:MachineApplicable(?)
Added in:1.50.0
Related Issues
View Source

suspicious_splitn📋
correctnessdeny

What it does

Checks for calls to [splitn](https://doc.rust-lang.org/std/primitive.str.html#method.splitn) andrelated functions with either zero or one splits.

Why is this bad?

These calls don’t actually split the value and arelikely to be intended as a different number.

Example

for x in s.splitn(1, ":") {    // ..}

Use instead:

for x in s.splitn(2, ":") {    // ..}
Applicability:Unspecified(?)
Added in:1.54.0
Related Issues
View Source

suspicious_to_owned📋
suspiciouswarn

What it does

Checks for the usage of_.to_owned(), on aCow<'_, _>.

Why is this bad?

Callingto_owned() on aCow creates a clone of theCowitself, without taking ownership of theCow contents (i.e.it’s equivalent to callingCow::clone).The similarly namedinto_owned method, on the other hand,clones theCow contents, effectively turning anyCow::Borrowedinto aCow::Owned.

Given the potential ambiguity, consider replacingto_ownedwithclone for better readability or, if getting aCow::Ownedwas the original intent, usinginto_owned instead.

Example

let s = "Hello world!";let cow = Cow::Borrowed(s);let data = cow.to_owned();assert!(matches!(data, Cow::Borrowed(_)))

Use instead:

let s = "Hello world!";let cow = Cow::Borrowed(s);let data = cow.clone();assert!(matches!(data, Cow::Borrowed(_)))

or

let s = "Hello world!";let cow = Cow::Borrowed(s);let _data: String = cow.into_owned();
Applicability:MaybeIncorrect(?)
Added in:1.65.0
Related Issues
View Source

suspicious_unary_op_formatting📋
suspiciouswarn

What it does

Checks the formatting of a unary operator on the right hand sideof a binary operator. It lints if there is no space between the binary and unary operators,but there is a space between the unary and its operand.

Why is this bad?

This is either a typo in the binary operator or confusing.

Example

// &&! looks like a different operatorif foo &&! bar {}

Use instead:

if foo && !bar {}
Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

suspicious_xor_used_as_pow📋
restrictionallow

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 restrict this?

It’s most probably a typo and may lead to unexpected behaviours.

Example

let x = 3_i32 ^ 4_i32;

Use instead:

let x = 3_i32.pow(4);
Applicability:MaybeIncorrect(?)
Added in:1.67.0
Related Issues
View Source

swap_ptr_to_ref📋
suspiciouswarn

What it does

Checks for calls tocore::mem::swap where either parameter is derived from a pointer

Why is this bad?

When at least one parameter toswap is derived from a pointer it may overlap with theother. This would then lead to undefined behavior.

Example

unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {    for (&x, &y) in x.iter().zip(y) {        core::mem::swap(&mut *x, &mut *y);    }}

Use instead:

unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {    for (&x, &y) in x.iter().zip(y) {        core::ptr::swap(x, y);    }}
Applicability:MachineApplicable(?)
Added in:1.63.0
Related Issues
View Source

swap_with_temporary📋
complexitywarn

What it does

Checks for usage ofstd::mem::swap with temporary values.

Why is this bad?

Storing a new value in place of a temporary value which willbe dropped right after theswap is an inefficient way of performingan assignment. The same result can be achieved by using a regularassignment.

Examples

fn replace_string(s: &mut String) {    std::mem::swap(s, &mut String::from("replaced"));}

Use instead:

fn replace_string(s: &mut String) {    *s = String::from("replaced");}

Also, swapping two temporary values has no effect, as they willboth be dropped right after swapping them. This is likely an indicationof a bug. For example, the following code swaps the references tothe last element of the vectors, instead of swapping the elementsthemselves:

fn bug(v1: &mut [i32], v2: &mut [i32]) {    // Incorrect: swapping temporary references (`&mut &mut` passed to swap)    std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap());}

Use instead:

fn correct(v1: &mut [i32], v2: &mut [i32]) {    std::mem::swap(v1.last_mut().unwrap(), v2.last_mut().unwrap());}
Applicability:MachineApplicable(?)
Added in:1.88.0
Related Issues
View Source

tabs_in_doc_comments📋
stylewarn

What it does

Checks doc comments for usage of tab characters.

Why is this bad?

The rust style-guide promotes spaces instead of tabs for indentation.To keep a consistent view on the source, also doc comments should not have tabs.Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when thedisplay settings of the author and reader differ.

Example

////// Struct to hold two strings:/// - firstone/// - secondonepub struct DoubleString {   ///   /// - First String:   /// - needs to be inside here   first_string: String,   ///   /// - Second String:   /// - needs to be inside here   second_string: String,}

Will be converted to:

////// Struct to hold two strings:///     - first        one///     - second    onepub struct DoubleString {   ///   ///     - First String:   ///         - needs to be inside here   first_string: String,   ///   ///     - Second String:   ///         - needs to be inside here   second_string: String,}
Applicability:MaybeIncorrect(?)
Added in:1.41.0
Related Issues
View Source

temporary_assignment📋
complexitywarn

What it does

Checks for construction of a structure or tuple just toassign a value in it.

Why is this bad?

Readability. If the structure is only created to beupdated, why not write the structure you want in the first place?

Example

(0, 0).0 = 1
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

test_attr_in_doctest📋
suspiciouswarn

What it does

Checks for#[test] in doctests unless they are marked witheitherignore,no_run orcompile_fail.

Why is this bad?

Code in examples marked as#[test] will somewhatsurprisingly not be run bycargo test. If you really wantto show how to test stuff in an example, mark itno_run tomake the intent clear.

Examples

/// An example of a doctest with a `main()` function////// # Examples////// ```/// #[test]/// fn equality_works() {///     assert_eq!(1_u8, 1);/// }/// ```fn test_attr_in_doctest() {    unimplemented!();}
Applicability:Unspecified(?)
Added in:1.76.0
Related Issues
View Source

tests_outside_test_module📋
restrictionallow

What it does

Triggers when a testing function (marked with the#[test] attribute) isn’t inside a testing module(marked with#[cfg(test)]).

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

#[test]fn my_cool_test() {    // [...]}#[cfg(test)]mod tests {    // [...]}

Use instead:

#[cfg(test)]mod tests {    #[test]    fn my_cool_test() {        // [...]    }}
Applicability:Unspecified(?)
Added in:1.70.0
Related Issues
View Source

to_digit_is_some📋
stylewarn

What it does

Checks for.to_digit(..).is_some() onchars.

Why is this bad?

This is a convoluted way of checking if achar is a digit. It’smore straight forward to use the dedicatedis_digit method.

Example

let is_digit = c.to_digit(radix).is_some();

can be written as:

let is_digit = c.is_digit(radix);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.41.0
Related Issues
View Source

to_string_in_format_args📋
perfwarn

What it does

Checks forToString::to_stringapplied to a type that implementsDisplayin a macro that does formatting.

Why is this bad?

Since the type implementsDisplay, the use ofto_string isunnecessary.

Example

println!("error: something failed at {}", Location::caller().to_string());

Use instead:

println!("error: something failed at {}", Location::caller());
Applicability:MachineApplicable(?)
Added in:1.58.0
Related Issues
View Source

to_string_trait_impl📋
stylewarn

What it does

Checks for direct implementations ofToString.

Why is this bad?

This trait is automatically implemented for any type which implements theDisplay trait.As such,ToString shouldn’t be implemented directly:Display should be implemented instead,and you get theToString implementation for free.

Example

struct Point {  x: usize,  y: usize,}impl ToString for Point {  fn to_string(&self) -> String {    format!("({}, {})", self.x, self.y)  }}

Use instead:

struct Point {  x: usize,  y: usize,}impl std::fmt::Display for Point {  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {    write!(f, "({}, {})", self.x, self.y)  }}
Applicability:Unspecified(?)
Added in:1.78.0
Related Issues
View Source

todo📋
restrictionallow

What it does

Checks for usage oftodo!.

Why restrict this?

Thetodo! macro indicates the presence of unfinished code,so it should not be present in production code.

Example

todo!();

Finish the implementation, or consider marking it as explicitly unimplemented.

unimplemented!();
Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

too_long_first_doc_paragraph📋
nurseryallow

What it does

Checks if the first paragraph in the documentation of items listed in the module page is too long.

Why is this bad?

Documentation will show the first paragraph of the docstring in the summary page of amodule. Having a nice, short summary in the first paragraph is part of writing good docs.

Example

/// A very short summary./// A much longer explanation that goes into a lot more detail about/// how the thing works, possibly with doclinks and so one,/// and probably spanning a many rows.struct Foo {}

Use instead:

/// A very short summary.////// A much longer explanation that goes into a lot more detail about/// how the thing works, possibly with doclinks and so one,/// and probably spanning a many rows.struct Foo {}
Applicability:MachineApplicable(?)
Added in:1.82.0
Related Issues
View Source

too_many_arguments📋
complexitywarn

What it does

Checks for functions with too many parameters.

Why is this bad?

Functions with lots of parameters are considered badstyle and reduce readability (“what does the 5th parameter mean?”). Considergrouping some parameters into a new type.

Example

fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {    // ..}

Configuration

  • too-many-arguments-threshold: The maximum number of argument a function or method can have

    (default:7)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

too_many_lines📋
pedanticallow

What it does

Checks for functions with a large amount of lines.

Why is this bad?

Functions with a lot of lines are harder to understanddue to having to look at a larger amount of code to understand what thefunction is doing. Consider splitting the body of the function intomultiple functions.

Example

fn im_too_long() {    println!("");    // ... 100 more LoC    println!("");}

Configuration

  • too-many-lines-threshold: The maximum number of lines a function or method can have

    (default:100)

Applicability:Unspecified(?)
Added in:1.34.0
Related Issues
View Source

toplevel_ref_arg📋
stylewarn

What it does

Checks for function arguments and let bindings denoted asref.

Why is this bad?

Theref declaration makes the function take an ownedvalue, but turns the argument into a reference (which means that the valueis destroyed when exiting the function). This adds not much value: eithertake a reference type, or take an owned value and create references in thebody.

For let bindings,let x = &foo; is preferred overlet ref x = foo. Thetype ofx is more obvious with the former.

Known problems

If the argument is dereferenced within the function,removing theref will lead to errors. This can be fixed by removing thedereferences, e.g., changing*x tox within the function.

Example

fn foo(ref _x: u8) {}

Use instead:

fn foo(_x: &u8) {}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

trailing_empty_array📋
nurseryallow

What it does

Displays a warning when a struct with a trailing zero-sized array is declared without arepr attribute.

Why is this bad?

Zero-sized arrays aren’t very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way,#[repr(C)] (or anotherrepr attribute) is needed.

Example

struct RarelyUseful {    some_field: u32,    last: [u32; 0],}

Use instead:

#[repr(C)]struct MoreOftenUseful {    some_field: usize,    last: [u32; 0],}
Applicability:Unspecified(?)
Added in:1.58.0
Related Issues
View Source

trait_duplication_in_bounds📋
nurseryallow

What it does

Checks for cases where generics or trait objects are being used and multiplesyntax specifications for trait bounds are used simultaneously.

Why is this bad?

Duplicate bounds makes the codeless readable than specifying them only once.

Example

fn func<T: Clone + Default>(arg: T) where T: Clone + Default {}

Use instead:

fn func<T: Clone + Default>(arg: T) {}// orfn func<T>(arg: T) where T: Clone + Default {}
fn foo<T: Default + Default>(bar: T) {}

Use instead:

fn foo<T: Default>(bar: T) {}
fn foo<T>(bar: T) where T: Default + Default {}

Use instead:

fn foo<T>(bar: T) where T: Default {}
Applicability:MachineApplicable(?)
Added in:1.47.0
Related Issues
View Source

transmute_bytes_to_str📋
complexitywarn

What it does

Checks for transmutes from a&[u8] to a&str.

Why is this bad?

Not every byte slice is a valid UTF-8 string.

Known problems

  • from_utf8 which this lint suggests using is slower thantransmuteas it needs to validate the input.If you are certain that the input is always a valid UTF-8,usefrom_utf8_unchecked which is as fast astransmutebut has a semantically meaningful name.
  • You might want to handle errors returned fromfrom_utf8 instead of callingunwrap.

Example

let b: &[u8] = &[1_u8, 2_u8];unsafe {    let _: &str = std::mem::transmute(b); // where b: &[u8]}// should be:let _ = std::str::from_utf8(b).unwrap();
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

transmute_int_to_bool📋
complexitywarn

What it does

Checks for transmutes from an integer to abool.

Why is this bad?

This might result in an invalid in-memory representation of abool.

Example

let x = 1_u8;unsafe {    let _: bool = std::mem::transmute(x); // where x: u8}// should be:let _: bool = x != 0;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

transmute_int_to_non_zero📋
complexitywarn

What it does

Checks for transmutes fromT toNonZero<T>, and suggests thenew_uncheckedmethod instead.

Why is this bad?

Transmutes work on any types and thus might cause unsoundness when those types changeelsewhere.new_unchecked only works for the appropriate types instead.

Example

let _: NonZero<u32> = unsafe { std::mem::transmute(123) };

Use instead:

let _: NonZero<u32> = unsafe { NonZero::new_unchecked(123) };
Applicability:Unspecified(?)
Added in:1.69.0
Related Issues
View Source

transmute_null_to_fn📋
correctnessdeny

What it does

Checks for null function pointer creation through transmute.

Why is this bad?

Creating a null function pointer is undefined behavior.

More info: https://doc.rust-lang.org/nomicon/ffi.html#the-nullable-pointer-optimization

Known problems

Not all cases can be detected at the moment of this writing.For example, variables which hold a null pointer and are then fed to atransmutecall, aren’t detectable yet.

Example

let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) };

Use instead:

let null_fn: Option<fn()> = None;
Applicability:Unspecified(?)
Added in:1.68.0
Related Issues
View Source

transmute_ptr_to_ptr📋
pedanticallow

What it does

Checks for transmutes from a pointer to a pointer, orfrom a reference to a reference.

Why is this bad?

Transmutes are dangerous, and these can instead bewritten as casts.

Example

let ptr = &1u32 as *const u32;unsafe {    // pointer-to-pointer transmute    let _: *const f32 = std::mem::transmute(ptr);    // ref-ref transmute    let _: &f32 = std::mem::transmute(&1u32);}// These can be respectively written:let _ = ptr as *const f32;let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

transmute_ptr_to_ref📋
complexitywarn

What it does

Checks for transmutes from a pointer to a reference.

Why is this bad?

This can always be rewritten with& and*.

Known problems

  • mem::transmute in statics and constants is stable from Rust 1.46.0,while dereferencing raw pointer is not stable yet.If you need to do this in those places,you would have to usetransmute instead.

Example

unsafe {    let _: &T = std::mem::transmute(p); // where p: *const T}// can be written:let _: &T = &*p;

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

transmute_undefined_repr📋
nurseryallow

What it does

Checks for transmutes between types which do not have a representation defined relative toeach other.

Why is this bad?

The results of such a transmute are not defined.

Known problems

This lint has had multiple problems in the past and was moved tonursery. See issue#8496 for more details.

Example

struct Foo<T>(u32, T);let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };

Use instead:

#[repr(C)]struct Foo<T>(u32, T);let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
Applicability:Unspecified(?)
Added in:1.60.0
Related Issues
View Source

transmutes_expressible_as_ptr_casts📋
complexitywarn

What it does

Checks for transmutes that could be a pointer cast.

Why is this bad?

Readability. The code tricks people into thinking thatsomething complex is going on.

Example

unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };

Use instead:

p as *const [u16];
Applicability:MachineApplicable(?)
Added in:1.47.0
Related Issues
View Source

transmuting_null📋
correctnessdeny

What it does

Checks for transmute calls which would receive a null pointer.

Why is this bad?

Transmuting a null pointer is undefined behavior.

Known problems

Not all cases can be detected at the moment of this writing.For example, variables which hold a null pointer and are then fed to atransmutecall, aren’t detectable yet.

Example

let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
Applicability:Unspecified(?)
Added in:1.35.0
Related Issues
View Source

trim_split_whitespace📋
stylewarn

What it does

Warns about callingstr::trim (or variants) beforestr::split_whitespace.

Why is this bad?

split_whitespace already ignores leading and trailing whitespace.

Example

" A B C ".trim().split_whitespace();

Use instead:

" A B C ".split_whitespace();
Applicability:MachineApplicable(?)
Added in:1.62.0
Related Issues
View Source

trivial_regex📋
nurseryallow

What it does

Checks for trivialregexcreation (withRegex::new,RegexBuilder::new, orRegexSet::new).

Why is this bad?

Matching the regex can likely be replaced by== orstr::starts_with,str::ends_with orstd::contains or otherstrmethods.

Known problems

If the same regex is going to be applied to multipleinputs, the precomputations done byRegex construction can givesignificantly better performance than any of thestr-based methods.

Example

Regex::new("^foobar")

Use instead:

str::starts_with("foobar")
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

trivially_copy_pass_by_ref📋
pedanticallow

What it does

Checks for functions taking arguments by reference, wherethe argument type isCopy and small enough to be more efficient to alwayspass by value.

Why is this bad?

In many calling conventions instances of structs willbe passed through registers if they fit into two or less general purposeregisters.

Known problems

This lint is target dependent, some cases will lint on 64-bit targets butnot 32-bit or lower targets.

The configuration optiontrivial_copy_size_limit can be set to overridethis limit for a project.

This lint attempts to allow passing arguments by reference if a referenceto that argument is returned. This is implemented by comparing the lifetimeof the argument and return value for equality. However, this can causefalse positives in cases involving multiple lifetimes that are bounded byeach other.

Also, it does not take account of other similar cases where getting memory addressesmatters; namely, returning the pointer to the argument in question,and passing the argument, as both references and pointers,to a function that needs the memory address. For further details, refer tothis issuethat explains a real case in which this false positiveled to anundefined behavior introduced with unsafe code.

Example

fn foo(v: &u32) {}

Use instead:

fn foo(v: u32) {}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

  • trivial-copy-size-limit: The maximum size (in bytes) to consider aCopy type for passing by value instead of byreference.

    (default:target_pointer_width)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

try_err📋
restrictionallow

What it does

Checks for usage ofErr(x)?.

Why restrict this?

The? operator is designed to allow calls thatcan fail to be easily chained. For example,foo()?.bar() orfoo(bar()?). BecauseErr(x)? can’t be used that way (it willalways return), it is more clear to writereturn Err(x).

Example

fn foo(fail: bool) -> Result<i32, String> {    if fail {      Err("failed")?;    }    Ok(0)}

Could be written:

fn foo(fail: bool) -> Result<i32, String> {    if fail {      return Err("failed".into());    }    Ok(0)}
Applicability:MachineApplicable(?)
Added in:1.38.0
Related Issues
View Source

tuple_array_conversions📋
nurseryallow

What it does

Checks for tuple<=>array conversions that are not done with.into().

Why is this bad?

It may be unnecessary complexity..into() works for converting tuples<=> arrays of up to12 elements and conveys the intent more clearly, while also leaving less room for hard tospot bugs!

Known issues

The suggested code may hide potential asymmetry in some cases. See#11085 for more info.

Example

let t1 = &[(1, 2), (3, 4)];let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect();

Use instead:

let t1 = &[(1, 2), (3, 4)];let v1: Vec<[u32; 2]> = t1.iter().map(|&t| t.into()).collect();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:Unspecified(?)
Added in:1.72.0
Related Issues
View Source

type_complexity📋
complexitywarn

What it does

Checks for types used in structs, parameters andletdeclarations above a certain complexity threshold.

Why is this bad?

Too complex types make the code less readable. Considerusing atype definition to simplify them.

Example

struct PointMatrixContainer {    matrix: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,}fn main() {    let point_matrix: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![        vec![            Box::new((1, 2, 3, 4)),            Box::new((5, 6, 7, 8)),        ],        vec![            Box::new((9, 10, 11, 12)),        ],    ];    let shared_point_matrix: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>> = Rc::new(point_matrix);    let container = PointMatrixContainer {        matrix: shared_point_matrix,    };    // ...}

Use instead:

Example

type PointMatrix = Vec<Vec<Box<(u32, u32, u32, u32)>>>;type SharedPointMatrix = Rc<PointMatrix>;struct PointMatrixContainer {    matrix: SharedPointMatrix,}fn main() {    let point_matrix: PointMatrix = vec![        vec![            Box::new((1, 2, 3, 4)),            Box::new((5, 6, 7, 8)),        ],        vec![            Box::new((9, 10, 11, 12)),        ],    ];    let shared_point_matrix: SharedPointMatrix = Rc::new(point_matrix);    let container = PointMatrixContainer {        matrix: shared_point_matrix,    };    // ...}

Configuration

  • type-complexity-threshold: The maximum complexity a type can have

    (default:250)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

type_id_on_box📋
suspiciouswarn

What it does

Looks for calls to.type_id() on aBox<dyn _>.

Why is this bad?

This almost certainly does not do what the user expects and can lead to subtle bugs.Calling.type_id() on aBox<dyn Trait> returns a fixedTypeId of theBox itself,rather than returning theTypeId of the underlying type behind the trait object.

ForBox<dyn Any> specifically (and trait objects that haveAny as its supertrait),this lint will provide a suggestion, which is to dereference the receiver explicitlyto go fromBox<dyn Any> todyn Any.This makes sure that.type_id() resolves to a dynamic call on the trait objectand not on the box.

If the fixedTypeId of theBox is the intended behavior, it’s better to be explicit about itand writeTypeId::of::<Box<dyn Trait>>():this makes it clear that a fixedTypeId is returned and not theTypeId of the implementor.

Example

use std::any::{Any, TypeId};let any_box: Box<dyn Any> = Box::new(42_i32);assert_eq!(any_box.type_id(), TypeId::of::<i32>()); // ⚠️ this fails!

Use instead:

use std::any::{Any, TypeId};let any_box: Box<dyn Any> = Box::new(42_i32);assert_eq!((*any_box).type_id(), TypeId::of::<i32>());//          ^ dereference first, to call `type_id` on `dyn Any`
Applicability:MaybeIncorrect(?)
Added in:1.73.0
Related Issues
View Source

type_repetition_in_bounds📋
nurseryallow

What it does

This lint warns about unnecessary type repetitions in trait bounds

Why is this bad?

Repeating the type for every bound makes the codeless readable than combining the bounds

Example

pub fn foo<T>(t: T) where T: Copy, T: Clone {}

Use instead:

pub fn foo<T>(t: T) where T: Copy + Clone {}

Configuration

  • max-trait-bounds: The maximum number of bounds a trait can have to be linted

    (default:3)

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:Unspecified(?)
Added in:1.38.0
Related Issues
View Source

unbuffered_bytes📋
perfwarn

What it does

Checks for calls toRead::bytes on types which don’t implementBufRead.

Why is this bad?

The default implementation callsread for each byte, which can be very inefficient for data that’s not in memory, such asFile.

Example

use std::io::Read;use std::fs::File;let file = File::open("./bytes.txt").unwrap();file.bytes();

Use instead:

use std::io::{BufReader, Read};use std::fs::File;let file = BufReader::new(File::open("./bytes.txt").unwrap());file.bytes();
Applicability:Unspecified(?)
Added in:1.87.0
Related Issues
View Source

unchecked_time_subtraction📋
pedanticallow

What it does

Lints subtraction between anInstant and aDuration, or between twoDuration values.

Why is this bad?

Unchecked subtraction could cause underflow on certain platforms, leading tounintentional panics.

Example

let time_passed = Instant::now() - Duration::from_secs(5);let dur1 = Duration::from_secs(3);let dur2 = Duration::from_secs(5);let diff = dur1 - dur2;

Use instead:

let time_passed = Instant::now().checked_sub(Duration::from_secs(5));let dur1 = Duration::from_secs(3);let dur2 = Duration::from_secs(5);let diff = dur1.checked_sub(dur2);

Past names

  • unchecked_duration_subtraction

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.67.0
Related Issues
View Source

unconditional_recursion📋
suspiciouswarn

What it does

Checks that there isn’t an infinite recursion in traitimplementations.

Why is this bad?

Infinite recursion in trait implementation will either cause crashesor result in an infinite loop, and it is hard to detect.

Example

enum Foo {    A,    B,}impl PartialEq for Foo {    fn eq(&self, other: &Self) -> bool {        self == other // bad!    }}

Use instead:

#[derive(PartialEq)]enum Foo {    A,    B,}

As an alternative, rewrite the logic without recursion:

enum Foo {    A,    B,}impl PartialEq for Foo {    fn eq(&self, other: &Self) -> bool {        matches!((self, other), (Foo::A, Foo::A) | (Foo::B, Foo::B))    }}
Applicability:Unspecified(?)
Added in:1.77.0
Related Issues
View Source

undocumented_unsafe_blocks📋
restrictionallow

What it does

Checks forunsafe blocks and impls without a// SAFETY: commentexplaining why the unsafe operations performed insidethe block are safe.

Note the comment must appear on the line(s) preceding the unsafe blockwith nothing appearing in between. The following is ok:

foo(    // SAFETY:    // This is a valid safety comment    unsafe { *x })

But neither of these are:

// SAFETY:// This is not a valid safety commentfoo(    /* SAFETY: Neither is this */ unsafe { *x },);

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

use std::ptr::NonNull;let a = &mut 42;let ptr = unsafe { NonNull::new_unchecked(a) };

Use instead:

use std::ptr::NonNull;let a = &mut 42;// SAFETY: references are guaranteed to be non-null.let ptr = unsafe { NonNull::new_unchecked(a) };

Configuration

  • accept-comment-above-attributes: Whether to accept a safety comment to be placed above the attributes for theunsafe block

    (default:true)

  • accept-comment-above-statement: Whether to accept a safety comment to be placed above the statement containing theunsafe block

    (default:true)

Applicability:Unspecified(?)
Added in:1.58.0
Related Issues
View Source

unicode_not_nfc📋
pedanticallow

What it does

Checks for string literals that contain Unicode in a formthat is not equal to itsNFC-recomposition.

Why is this bad?

If such a string is compared to another, the resultsmay be surprising.

Example

You may not see it, but “à”“ and “à”“ aren’t the same string. Theformer when escaped is actually"a\u{300}" while the latter is"\u{e0}".

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

unimplemented📋
restrictionallow

What it does

Checks for usage ofunimplemented!.

Why restrict this?

This macro, or panics in general, may be unwanted in production code.

Example

unimplemented!();
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

uninhabited_references📋
nurseryallow

What it does

It detects references to uninhabited types, such as! andwarns when those are either dereferenced or returned from a function.

Why is this bad?

Dereferencing a reference to an uninhabited type would createan instance of such a type, which cannot exist. This constitutesundefined behaviour. Such a reference could have been createdbyunsafe code.

Example

The following function can return a reference to an uninhabited type(Infallible) because it usesunsafe code to create it. However,the user of such a function could dereference the return value andtrigger an undefined behavior from safe code.

fn create_ref() -> &'static std::convert::Infallible {    unsafe { std::mem::transmute(&()) }}
Applicability:Unspecified(?)
Added in:1.76.0
Related Issues
View Source

uninit_assumed_init📋
correctnessdeny

What it does

Checks forMaybeUninit::uninit().assume_init().

Why is this bad?

For most types, this is undefined behavior.

Known problems

For now, we accept empty tuples and tuples / arraysofMaybeUninit. There may be other types that allow uninitializeddata, but those are not yet rigorously defined.

Example

// Beware the UBuse std::mem::MaybeUninit;let _: usize = unsafe { MaybeUninit::uninit().assume_init() };

Note that the following is OK:

use std::mem::MaybeUninit;let _: [MaybeUninit<bool>; 5] = unsafe {    MaybeUninit::uninit().assume_init()};
Applicability:Unspecified(?)
Added in:1.39.0
Related Issues
View Source

uninit_vec📋
correctnessdeny

What it does

Checks forset_len() call that createsVec with uninitialized elements.This is commonly caused by callingset_len() right after allocating orreserving a buffer withnew(),default(),with_capacity(), orreserve().

Why is this bad?

It creates aVec with uninitialized data, which leads toundefined behavior with most safe operations. Notably, uninitializedVec<u8> must not be used with genericRead.

Moreover, callingset_len() on aVec created withnew() ordefault()creates out-of-bound values that lead to heap memory corruption when used.

Known Problems

This lint only checks directly adjacent statements.

Example

let mut vec: Vec<u8> = Vec::with_capacity(1000);unsafe { vec.set_len(1000); }reader.read(&mut vec); // undefined behavior!

How to fix?

  1. Use an initialized buffer:
    let mut vec: Vec<u8> = vec![0; 1000];reader.read(&mut vec);
  2. Wrap the content inMaybeUninit:
    let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);vec.set_len(1000);  // `MaybeUninit` can be uninitialized
  3. If you are on 1.60.0 or later,Vec::spare_capacity_mut() is available:
    let mut vec: Vec<u8> = Vec::with_capacity(1000);let remaining = vec.spare_capacity_mut();  // `&mut [MaybeUninit<u8>]`// perform initialization with `remaining`vec.set_len(...);  // Safe to call `set_len()` on initialized part
Applicability:Unspecified(?)
Added in:1.58.0
Related Issues
View Source

uninlined_format_args📋
pedanticallow

What it does

Detect when a variable is not inlined in a format string,and suggests to inline it.

Why is this bad?

Non-inlined code is slightly more difficult to read and understand,as it requires arguments to be matched against the format string.The inlined syntax, where allowed, is simpler.

Example

format!("{}", var);format!("{:?}", var);format!("{v:?}", v = var);format!("{0} {0}", var);format!("{0:1$}", var, width);format!("{:.*}", prec, var);

Use instead:

format!("{var}");format!("{var:?}");format!("{var:?}");format!("{var} {var}");format!("{var:width$}");format!("{var:.prec$}");

Ifallow-mixed-uninlined-format-args is set tofalse in clippy.toml,the following code will also trigger the lint:

format!("{} {}", var, 1+2);

Use instead:

format!("{var} {}", 1+2);

Known Problems

If a format string contains a numbered argument that cannot be inlinednothing will be suggested, e.g.println!("{0}={1}", var, 1+2).

Configuration

  • allow-mixed-uninlined-format-args: Whether to allow mixed uninlined format args, e.g.format!("{} {}", a, foo.bar)

    (default:true)

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.66.0
Related Issues
View Source

unit_arg📋
complexitywarn

What it does

Checks for passing a unit value as an argument to a function without using aunit literal (()).

Why is this bad?

This is likely the result of an accidental semicolon.

Example

foo({    let a = bar();    baz(a);})
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

unit_cmp📋
correctnessdeny

What it does

Checks for comparisons to unit. This includes all binarycomparisons (like== and<) and asserts.

Why is this bad?

Unit is always equal to itself, and thus is just aclumsily written constant. Mostly this happens when someone accidentallyadds semicolons at the end of the operands.

Example

if {    foo();} == {    bar();} {    baz();}

is equal to

{    foo();    bar();    baz();}

For asserts:

assert_eq!({ foo(); }, { bar(); });

will always succeed

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

unit_hash📋
correctnessdeny

What it does

Detects().hash(_).

Why is this bad?

Hashing a unit value doesn’t do anything as the implementation ofHash for() is a no-op.

Example

match my_enum {Empty => ().hash(&mut state),WithValue(x) => x.hash(&mut state),}

Use instead:

match my_enum {Empty => 0_u8.hash(&mut state),WithValue(x) => x.hash(&mut state),}
Applicability:MaybeIncorrect(?)
Added in:1.58.0
Related Issues
View Source

unit_return_expecting_ord📋
correctnessdeny

What it does

Checks for functions that expect closures of typeFn(…) -> Ord where the implemented closure returns the unit type.The lint also suggests to remove the semi-colon at the end of the statement if present.

Why is this bad?

Likely, returning the unit type is unintentional, andcould simply be caused by an extra semi-colon. Since () implements Ordit doesn’t cause a compilation error.This is the same reasoning behind the unit_cmp lint.

Known problems

If returning unit is intentional, then there is noway of specifying this without triggering needless_return lint

Example

let mut twins = vec![(1, 1), (2, 2)];twins.sort_by_key(|x| { x.1; });
Applicability:Unspecified(?)
Added in:1.47.0
Related Issues
View Source

unnecessary_box_returns📋
pedanticallow

What it does

Checks for a return type containing aBox<T> whereT implementsSized

The lint ignoresBox<T> whereT is larger thanunnecessary_box_size,as returning a largeT directly may be detrimental to performance.

Why is this bad?

It’s better to just returnT in these cases. The caller may not needthe value to be boxed, and it’s expensive to free the memory once theBox<T> been dropped.

Example

fn foo() -> Box<String> {    Box::new(String::from("Hello, world!"))}

Use instead:

fn foo() -> String {    String::from("Hello, world!")}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

  • unnecessary-box-size: The byte size aT inBox<T> can have, below which it triggers theclippy::unnecessary_box lint

    (default:128)

Applicability:Unspecified(?)
Added in:1.70.0
Related Issues
View Source

unnecessary_cast📋
complexitywarn

What it does

Checks for casts to the same type, casts of int literals to integertypes, casts of float literals to float types, and casts between rawpointers that don’t change type or constness.

Why is this bad?

It’s just unnecessary.

Known problems

When the expression on the left is a function call, the lint considersthe return type to be a type alias if it’s aliased through ausestatement (likeuse std::io::Result as IoResult). It will not lintsuch cases.

This check will only work on primitive types without any intermediatereferences: raw pointers and trait objects may or may not work.

Example

let _ = 2i32 as i32;let _ = 0.5 as f32;

Better:

let _ = 2_i32;let _ = 0.5_f32;
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

unnecessary_clippy_cfg📋
suspiciouswarn

What it does

Checks for#[cfg_attr(clippy, allow(clippy::lint))]and suggests to replace it with#[allow(clippy::lint)].

Why is this bad?

There is no reason to put clippy attributes behind a clippycfg as they are notrun by anything else than clippy.

Example

#![cfg_attr(clippy, allow(clippy::deprecated_cfg_attr))]

Use instead:

#![allow(clippy::deprecated_cfg_attr)]
Applicability:MachineApplicable(?)
Added in:1.78.0
Related Issues
View Source

unnecessary_debug_formatting📋
pedanticallow

What it does

Checks forDebug formatting ({:?}) applied to anOsStr orPath.

Why is this bad?

Rust doesn’t guarantee whatDebug formatting looks like, and it couldchange in the future.OsStrs andPaths can beDisplay formattedusing theirdisplay methods.

Furthermore, withDebug formatting, certain characters are escaped.Thus, aDebug formattedPath is less likely to be clickable.

Example

let path = Path::new("...");println!("The path is {:?}", path);

Use instead:

let path = Path::new("…");println!("The path is {}", path.display());
Applicability:Unspecified(?)
Added in:1.87.0
Related Issues
View Source

unnecessary_fallible_conversions📋
stylewarn

What it does

Checks for calls toTryInto::try_into andTryFrom::try_from when their infallible counterpartscould be used.

Why is this bad?

In those cases, theTryInto andTryFrom trait implementation is a blanket impl that forwardstoInto orFrom, which always succeeds.The returnedResult<_, Infallible> requires error handling to get the contained valueeven though the conversion can never fail.

Example

let _: Result<i64, _> = 1i32.try_into();let _: Result<i64, _> = <_>::try_from(1i32);

Usefrom/into instead:

let _: i64 = 1i32.into();let _: i64 = <_>::from(1i32);
Applicability:MachineApplicable(?)
Added in:1.75.0
Related Issues
View Source

unnecessary_filter_map📋
complexitywarn

What it does

Checks forfilter_map calls that could be replaced byfilter ormap.More specifically it checks if the closure provided is only performing one of thefilter or map operations and suggests the appropriate option.

Why is this bad?

Complexity. The intent is also clearer if only a singleoperation is being performed.

Example

let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });// As there is no transformation of the argument this could be written as:let _ = (0..3).filter(|&x| x > 2);
let _ = (0..4).filter_map(|x| Some(x + 1));// As there is no conditional check on the argument this could be written as:let _ = (0..4).map(|x| x + 1);
Applicability:Unspecified(?)
Added in:1.31.0
Related Issues
View Source

unnecessary_find_map📋
complexitywarn

What it does

Checks forfind_map calls that could be replaced byfind ormap. Morespecifically it checks if the closure provided is only performing one of thefind or map operations and suggests the appropriate option.

Why is this bad?

Complexity. The intent is also clearer if only a singleoperation is being performed.

Example

let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None });// As there is no transformation of the argument this could be written as:let _ = (0..3).find(|&x| x > 2);
let _ = (0..4).find_map(|x| Some(x + 1));// As there is no conditional check on the argument this could be written as:let _ = (0..4).map(|x| x + 1).next();
Applicability:Unspecified(?)
Added in:1.61.0
Related Issues
View Source

unnecessary_first_then_check📋
complexitywarn

What it does

Checks the usage of.first().is_some() or.first().is_none() to check if a slice isempty.

Why is this bad?

Using.is_empty() is shorter and better communicates the intention.

Example

let v = vec![1, 2, 3];if v.first().is_none() {    // The vector is empty...}

Use instead:

let v = vec![1, 2, 3];if v.is_empty() {    // The vector is empty...}
Applicability:MachineApplicable(?)
Added in:1.83.0
Related Issues
View Source

unnecessary_fold📋
stylewarn

What it does

Checks for usage offold when a more succinct alternative exists.Specifically, this checks forfolds which could be replaced byany,all,sum orproduct.

Why is this bad?

Readability.

Example

(0..3).fold(false, |acc, x| acc || x > 2);

Use instead:

(0..3).any(|x| x > 2);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

unnecessary_get_then_check📋
suspiciouswarn

What it does

Checks the usage of.get().is_some() or.get().is_none() on std map types.

Why is this bad?

It can be done in one call with.contains()/.contains_key().

Example

let s: HashSet<String> = HashSet::new();if s.get("a").is_some() {    // code}

Use instead:

let s: HashSet<String> = HashSet::new();if s.contains("a") {    // code}
Applicability:MaybeIncorrect(?)
Added in:1.78.0
Related Issues
View Source

unnecessary_join📋
pedanticallow

What it does

Checks for usage of.collect::<Vec<String>>().join("") on iterators.

Why is this bad?

.collect::<String>() is more concise and might be more performant

Example

let vector = vec!["hello",  "world"];let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join("");println!("{}", output);

The correct use would be:

let vector = vec!["hello",  "world"];let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>();println!("{}", output);

Known problems

While.collect::<String>() is sometimes more performant, there are cases whereusing.collect::<String>() over.collect::<Vec<String>>().join("")will prevent loop unrolling and will result in a negative performance impact.

Additionally, differences have been observed between aarch64 and x86_64 assembly output,with aarch64 tending to producing faster assembly in more cases when using.collect::<String>()

Applicability:MachineApplicable(?)
Added in:1.61.0
Related Issues
View Source

unnecessary_lazy_evaluations📋
stylewarn

What it does

As the counterpart toor_fun_call, this lint looks for unnecessarylazily evaluated closures onOption andResult.

This lint suggests changing the following functions, when eager evaluation results insimpler code:

  • unwrap_or_else tounwrap_or
  • and_then toand
  • or_else toor
  • get_or_insert_with toget_or_insert
  • ok_or_else took_or
  • then tothen_some (for msrv >= 1.62.0)

Why is this bad?

Using eager evaluation is shorter and simpler in some cases.

Known problems

It is possible, but not recommended forDeref andIndex to haveside effects. Eagerly evaluating them can change the semantics of the program.

Example

let opt: Option<u32> = None;opt.unwrap_or_else(|| 42);

Use instead:

let opt: Option<u32> = None;opt.unwrap_or(42);

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.48.0
Related Issues
View Source

unnecessary_literal_bound📋
pedanticallow

What it does

Detects functions that are written to return&str that could return&'static str but instead return a&'a str.

Why is this bad?

This leaves the caller unable to use the&str as&'static str, causing unnecessary allocations or confusion.This is also most likely what you meant to write.

Example

impl MyType {    fn returns_literal(&self) -> &str {        "Literal"    }}

Use instead:

impl MyType {    fn returns_literal(&self) -> &'static str {        "Literal"    }}

Or, in case you may return a non-literalstr in future:

impl MyType {    fn returns_literal<'a>(&'a self) -> &'a str {        "Literal"    }}
Applicability:MachineApplicable(?)
Added in:1.84.0
Related Issues
View Source

unnecessary_literal_unwrap📋
complexitywarn

What it does

Checks for.unwrap() related calls onResults andOptions that are constructed.

Why is this bad?

It is better to write the value directly without the indirection.

Examples

let val1 = Some(1).unwrap();let val2 = Ok::<_, ()>(1).unwrap();let val3 = Err::<(), _>(1).unwrap_err();

Use instead:

let val1 = 1;let val2 = 1;let val3 = 1;
Applicability:MachineApplicable(?)
Added in:1.72.0
Related Issues
View Source

unnecessary_map_on_constructor📋
complexitywarn

What it does

Suggests removing the use of amap() (ormap_err()) method when anOption orResultis being constructed.

Why is this bad?

It introduces unnecessary complexity. Instead, the function can be called beforeconstructing theOption orResult from its return value.

Example

Some(4).map(i32::swap_bytes)

Use instead:

Some(i32::swap_bytes(4))
Applicability:MachineApplicable(?)
Added in:1.74.0
Related Issues
View Source

unnecessary_map_or📋
stylewarn

What it does

Converts some constructs mapping an Enum value for equality comparison.

Why is this bad?

Calls such asopt.map_or(false, |val| val == 5) are needlessly long and cumbersome,and can be reduced to, for example,opt == Some(5) assumingopt implementsPartialEq.Also, calls such asopt.map_or(true, |val| val == 5) can be reduced toopt.is_none_or(|val| val == 5).This lint offers readability and conciseness improvements.

Example

pub fn a(x: Option<i32>) -> (bool, bool) {    (        x.map_or(false, |n| n == 5),        x.map_or(true, |n| n > 5),    )}

Use instead:

pub fn a(x: Option<i32>) -> (bool, bool) {    (        x == Some(5),        x.is_none_or(|n| n > 5),    )}
Applicability:MachineApplicable(?)
Added in:1.84.0
Related Issues
View Source

unnecessary_min_or_max📋
complexitywarn

What it does

Checks for unnecessary calls tomin() ormax() in the following cases

  • Either both side is constant
  • One side is clearly larger than the other, like i32::MIN and an i32 variable

Why is this bad?

In the aforementioned cases it is not necessary to callmin() ormax()to compare values, it may even cause confusion.

Example

let _ = 0.min(7_u32);

Use instead:

let _ = 0;
Applicability:MachineApplicable(?)
Added in:1.81.0
Related Issues
View Source

unnecessary_mut_passed📋
stylewarn

What it does

Detects passing a mutable reference to a function that onlyrequires an immutable reference.

Why is this bad?

The mutable reference rules out all other references tothe value. Also the code misleads about the intent of the call site.

Example

vec.push(&mut value);

Use instead:

vec.push(&value);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

unnecessary_operation📋
complexitywarn

What it does

Checks for expression statements that can be reduced to asub-expression.

Why is this bad?

Expressions by themselves often have no side-effects.Having such expressions reduces readability.

Example

compute_array()[0];
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

unnecessary_option_map_or_else📋
suspiciouswarn

Checks for usage of.map_or_else() “map closure” forOption type.

Why is this bad?

This can be written more concisely by usingunwrap_or_else().

Example

let k = 10;let x: Option<u32> = Some(4);let y = x.map_or_else(|| 2 * k, |n| n);

Use instead:

let k = 10;let x: Option<u32> = Some(4);let y = x.unwrap_or_else(|| 2 * k);
Applicability:MachineApplicable(?)
Added in:1.88.0
Related Issues
View Source

unnecessary_owned_empty_strings📋
stylewarn

What it does

Detects cases of owned empty strings being passed as an argument to a function expecting&str

Why is this bad?

This results in longer and less readable code

Example

vec!["1", "2", "3"].join(&String::new());

Use instead:

vec!["1", "2", "3"].join("");
Applicability:MachineApplicable(?)
Added in:1.62.0
Related Issues
View Source

unnecessary_result_map_or_else📋
suspiciouswarn

What it does

Checks for usage of.map_or_else() “map closure” forResult type.

Why is this bad?

This can be written more concisely by usingunwrap_or_else().

Example

let x: Result<u32, ()> = Ok(0);let y = x.map_or_else(|err| handle_error(err), |n| n);

Use instead:

let x: Result<u32, ()> = Ok(0);let y = x.unwrap_or_else(|err| handle_error(err));
Applicability:MachineApplicable(?)
Added in:1.78.0
Related Issues
View Source

unnecessary_safety_comment📋
restrictionallow

What it does

Checks for// SAFETY: comments on safe code.

Why restrict this?

Safe code has no safety requirements, so there is no need todescribe safety invariants.

Example

use std::ptr::NonNull;let a = &mut 42;// SAFETY: references are guaranteed to be non-null.let ptr = NonNull::new(a).unwrap();

Use instead:

use std::ptr::NonNull;let a = &mut 42;let ptr = NonNull::new(a).unwrap();
Applicability:MachineApplicable(?)
Added in:1.67.0
Related Issues
View Source

unnecessary_safety_doc📋
restrictionallow

What it does

Checks for the doc comments of publicly visiblesafe functions and traits and warns if there is a# Safety section.

Why restrict this?

Safe functions and traits are safe to implement and therefore do notneed to describe safety preconditions that users are required to uphold.

Examples

/// # Safety////// This function should not be called before the horsemen are ready.pub fn start_apocalypse_but_safely(u: &mut Universe) {    unimplemented!();}

The function is safe, so there shouldn’t be any preconditionsthat have to be explained for safety reasons.

/// This function should really be documentedpub fn start_apocalypse(u: &mut Universe) {    unimplemented!();}

Configuration

  • check-private-items: Whether to also run the listed lints on private items.

    (default:false)

Applicability:Unspecified(?)
Added in:1.67.0
Related Issues
View Source

unnecessary_self_imports📋
restrictionallow

What it does

Checks for imports ending in::{self}.

Why restrict this?

In most cases, this can be written much more cleanly by omitting::{self}.

Known problems

Removing::{self} will cause any non-module items at the same path to also be imported.This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attemptto detect this scenario and that is why it is a restriction lint.

Example

use std::io::{self};

Use instead:

use std::io;
Applicability:MaybeIncorrect(?)
Added in:1.53.0
Related Issues
View Source

unnecessary_semicolon📋
pedanticallow

What it does

Checks for the presence of a semicolon at the end ofamatch orif statement evaluating to().

Why is this bad?

The semicolon is not needed, and may be removed toavoid confusion and visual clutter.

Example

if a > 10 {    println!("a is greater than 10");};

Use instead:

if a > 10 {    println!("a is greater than 10");}
Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

unnecessary_sort_by📋
complexitywarn

What it does

Checks for usage ofVec::sort_by passing in a closurewhich compares the two arguments, either directly or indirectly.

Why is this bad?

It is more clear to useVec::sort_by_key (orVec::sort ifpossible) than to useVec::sort_by and a more complicatedclosure.

Known problems

If the suggestedVec::sort_by_key uses Reverse and it isn’t alreadyimported by a use statement, then it will need to be added manually.

Example

vec.sort_by(|a, b| a.foo().cmp(&b.foo()));

Use instead:

vec.sort_by_key(|a| a.foo());
Applicability:MachineApplicable(?)
Added in:1.46.0
Related Issues
View Source

unnecessary_struct_initialization📋
nurseryallow

What it does

Checks for initialization of an identicalstruct from another instanceof the type, either by copying a base without setting any field or bymoving all fields individually.

Why is this bad?

Readability suffers from unnecessary struct building.

Example

struct S { s: String }let a = S { s: String::from("Hello, world!") };let b = S { ..a };

Use instead:

struct S { s: String }let a = S { s: String::from("Hello, world!") };let b = a;

The struct literalS { ..a } in the assignment tob could be replacedwith justa.

Known Problems

Has false positives when the base is a place expression that cannot bemoved out of, see#10547.

Empty structs are ignored by the lint.

Applicability:MachineApplicable(?)
Added in:1.70.0
Related Issues
View Source

unnecessary_to_owned📋
perfwarn

What it does

Checks for unnecessary calls toToOwned::to_ownedand otherto_owned-like functions.

Why is this bad?

The unnecessary calls result in useless allocations.

Known problems

unnecessary_to_owned can falsely trigger ifIntoIterator::into_iter is applied to anowned copy of a resource and the resource is later used mutably. See#8148.

Example

let path = std::path::Path::new("x");foo(&path.to_string_lossy().to_string());fn foo(s: &str) {}

Use instead:

let path = std::path::Path::new("x");foo(&path.to_string_lossy());fn foo(s: &str) {}
Applicability:MachineApplicable(?)
Added in:1.59.0
Related Issues
View Source

unnecessary_unwrap📋
complexitywarn

What it does

Checks for calls ofunwrap[_err]() that cannot fail.

Why is this bad?

Usingif let ormatch is more idiomatic.

Example

if option.is_some() {    do_something_with(option.unwrap())}

Could be written:

if let Some(value) = option {    do_something_with(value)}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

unnecessary_wraps📋
pedanticallow

What it does

Checks for private functions that only returnOk orSome.

Why is this bad?

It is not meaningful to wrap values when noNone orErr is returned.

Known problems

There can be false positives if the function signature is designed tofit some external requirement.

Example

fn get_cool_number(a: bool, b: bool) -> Option<i32> {    if a && b {        return Some(50);    }    if a {        Some(0)    } else {        Some(10)    }}

Use instead:

fn get_cool_number(a: bool, b: bool) -> i32 {    if a && b {        return 50;    }    if a {        0    } else {        10    }}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:MaybeIncorrect(?)
Added in:1.50.0
Related Issues
View Source

unneeded_field_pattern📋
restrictionallow

What it does

Checks for structure field patterns bound to wildcards.

Why restrict this?

Using.. instead is shorter and leaves the focus onthe fields that are actually bound.

Example

let f = Foo { a: 0, b: 0, c: 0 };match f {    Foo { a: _, b: 0, .. } => {},    Foo { a: _, b: _, c: _ } => {},}

Use instead:

let f = Foo { a: 0, b: 0, c: 0 };match f {    Foo { b: 0, .. } => {},    Foo { .. } => {},}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

unneeded_struct_pattern📋
stylewarn

What it does

Checks for struct patterns that match against unit variant.

Why is this bad?

Struct pattern{ } or{ .. } is not needed for unit variant.

Example

match Some(42) {    Some(v) => v,    None { .. } => 0,};// Ormatch Some(42) {    Some(v) => v,    None { } => 0,};

Use instead:

match Some(42) {    Some(v) => v,    None => 0,};
Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

unneeded_wildcard_pattern📋
complexitywarn

What it does

Checks for tuple patterns with a wildcardpattern (_) is next to a rest pattern (..).

NOTE: While_, .. means there is at least one element left,..means there are 0 or more elements left. This can make a differencewhen refactoring, but shouldn’t result in errors in the refactored code,since the wildcard pattern isn’t used anyway.

Why is this bad?

The wildcard pattern is unneeded as the rest patterncan match that element as well.

Example

match t {    TupleStruct(0, .., _) => (),    _ => (),}

Use instead:

match t {    TupleStruct(0, ..) => (),    _ => (),}
Applicability:MachineApplicable(?)
Added in:1.40.0
Related Issues
View Source

unnested_or_patterns📋
pedanticallow

What it does

Checks for unnested or-patterns, e.g.,Some(0) | Some(2) andsuggests replacing the pattern with a nested one,Some(0 | 2).

Another way to think of this is that it rewrites patterns indisjunctive normal form (DNF) intoconjunctive normal form (CNF).

Why is this bad?

In the example above,Some is repeated, which unnecessarily complicates the pattern.

Example

fn main() {    if let Some(0) | Some(2) = Some(0) {}}

Use instead:

fn main() {    if let Some(0 | 2) = Some(0) {}}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.46.0
Related Issues
View Source

unreachable📋
restrictionallow

What it does

Checks for usage ofunreachable!.

Why restrict this?

This macro, or panics in general, may be unwanted in production code.

Example

unreachable!();
Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

unreadable_literal📋
pedanticallow

What it does

Warns if a long integral or floating-point constant doesnot contain underscores.

Why is this bad?

Reading long numbers is difficult without separators.

Example

61864918973511

Use instead:

61_864_918_973_511

Configuration

  • unreadable-literal-lint-fractions: Should the fraction of a decimal be linted to include separators.

    (default:true)

Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

unsafe_derive_deserialize📋
pedanticallow

What it does

Checks for derivingserde::Deserialize on a type thathas methods usingunsafe.

Why is this bad?

Derivingserde::Deserialize will create a constructorthat may violate invariants held by another constructor.

Example

use serde::Deserialize;#[derive(Deserialize)]pub struct Foo {    // ..}impl Foo {    pub fn new() -> Self {        // setup here ..    }    pub unsafe fn parts() -> (&str, &str) {        // assumes invariants hold    }}
Applicability:Unspecified(?)
Added in:1.45.0
Related Issues
View Source

unsafe_removed_from_name📋
stylewarn

What it does

Checks for imports that remove “unsafe” from an item’sname.

Why is this bad?

Renaming makes it less clear which traits andstructures are unsafe.

Example

use std::cell::{UnsafeCell as TotallySafeCell};extern crate crossbeam;use crossbeam::{spawn_unsafe as spawn};
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

unsafe_vector_initialization📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

The suggested alternative could be substantially slower.

Applicability:Unspecified(?)
Deprecated in:pre 1.29.0
Related Issues

unseparated_literal_suffix📋
restrictionallow

What it does

Warns if literal suffixes are not separated by anunderscore.To enforce unseparated literal suffix style,see theseparated_literal_suffix lint.

Why restrict this?

Suffix style should be consistent.

Example

123832i32

Use instead:

123832_i32
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

unsound_collection_transmute📋
correctnessdeny

What it does

Checks for transmutes between collections whosetypes have different ABI, size or alignment.

Why is this bad?

This is undefined behavior.

Known problems

Currently, we cannot know whether a type is acollection, so we just lint the ones that come withstd.

Example

// different size, therefore likely out-of-bounds memory access// You absolutely do not want this in your code!unsafe {    std::mem::transmute::<_, Vec<u32>>(vec![2_u16])};

You must always iterate, map and collect the values:

vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

unstable_as_mut_slice📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

Vec::as_mut_slice is now stable.

Applicability:Unspecified(?)
Deprecated in:pre 1.29.0
Related Issues

unstable_as_slice📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

Vec::as_slice is now stable.

Applicability:Unspecified(?)
Deprecated in:pre 1.29.0
Related Issues

unused_async📋
pedanticallow

What it does

Checks for functions that are declaredasync but have no.awaits inside of them.

Why is this bad?

Async functions with no async code create overhead, both mentally and computationally.Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of whichcauses runtime overhead and hassle for the caller.

Example

async fn get_random_number() -> i64 {    4 // Chosen by fair dice roll. Guaranteed to be random.}let number_future = get_random_number();

Use instead:

fn get_random_number_improved() -> i64 {    4 // Chosen by fair dice roll. Guaranteed to be random.}let number_future = async { get_random_number_improved() };
Applicability:Unspecified(?)
Added in:1.54.0
Related Issues
View Source

unused_collect📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

Iterator::collect is now marked as#[must_use].

Applicability:Unspecified(?)
Deprecated in:1.39.0
Related Issues

unused_enumerate_index📋
stylewarn

What it does

Checks for uses of theenumerate method where the index is unused (_)

Why is this bad?

The index from.enumerate() is immediately dropped.

Example

let v = vec![1, 2, 3, 4];for (_, x) in v.iter().enumerate() {    println!("{x}");}

Use instead:

let v = vec![1, 2, 3, 4];for x in v.iter() {    println!("{x}");}
Applicability:MachineApplicable(?)
Added in:1.75.0
Related Issues
View Source

unused_format_specs📋
complexitywarn

What it does

Detectsformatting parameters that have no effect on the output offormat!(),println!() or similar macros.

Why is this bad?

Shorter format specifiers are easier to read, it may also indicate thatan expected formatting operation such as adding padding isn’t happening.

Example

println!("{:.}", 1.0);println!("not padded: {:5}", format_args!("..."));

Use instead:

println!("{}", 1.0);println!("not padded: {}", format_args!("..."));// ORprintln!("padded: {:5}", format!("..."));
Applicability:MaybeIncorrect(?)
Added in:1.66.0
Related Issues
View Source

unused_io_amount📋
correctnessdeny

What it does

Checks for unused written/read amount.

Why is this bad?

io::Write::write(_vectored) andio::Read::read(_vectored) are not guaranteed toprocess the entire buffer. They return how many bytes were processed, whichmight be smallerthan a given buffer’s length. If you don’t need to deal withpartial-write/read, usewrite_all/read_exact instead.

When working with asynchronous code (either with thefuturescrate or withtokio), a similar issue exists forAsyncWriteExt::write() andAsyncReadExt::read() : thesefunctions are also not guaranteed to process the entirebuffer. Your code should either handle partial-writes/reads, orcall thewrite_all/read_exact methods on those traits instead.

Known problems

Detects only common patterns.

Examples

use std::io;fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {    w.write(b"foo")?;    Ok(())}

Use instead:

use std::io;fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {    w.write_all(b"foo")?;    Ok(())}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

unused_peekable📋
nurseryallow

What it does

Checks for the creation of apeekable iterator that is never.peek()ed

Why is this bad?

Creating a peekable iterator without using any of its methods is likely a mistake,or just a leftover after a refactor.

Example

let collection = vec![1, 2, 3];let iter = collection.iter().peekable();for item in iter {    // ...}

Use instead:

let collection = vec![1, 2, 3];let iter = collection.iter();for item in iter {    // ...}
Applicability:Unspecified(?)
Added in:1.65.0
Related Issues
View Source

unused_result_ok📋
restrictionallow

What it does

Checks for calls toResult::ok() without using the returnedOption.

Why is this bad?

UsingResult::ok() may look like the result is checked likeunwrap orexpect would dobut it only silences the warning caused by#[must_use] on theResult.

Example

some_function().ok();

Use instead:

let _ = some_function();
Applicability:MaybeIncorrect(?)
Added in:1.82.0
Related Issues
View Source

unused_rounding📋
nurseryallow

What it does

Detects cases where a whole-number literal float is being rounded, usingthefloor,ceil, orround methods.

Why is this bad?

This is unnecessary and confusing to the reader. Doing this is probably a mistake.

Example

let x = 1f32.ceil();

Use instead:

let x = 1f32;
Applicability:MachineApplicable(?)
Added in:1.63.0
Related Issues
View Source

unused_self📋
pedanticallow

What it does

Checks methods that contain aself argument but don’t use it

Why is this bad?

It may be clearer to define the method as an associated function insteadof an instance method if it doesn’t requireself.

Example

struct A;impl A {    fn method(&self) {}}

Could be written:

struct A;impl A {    fn method() {}}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:1.40.0
Related Issues
View Source

unused_trait_names📋
restrictionallow

What it does

Checks foruse Trait where the Trait is only used for its methods and not referenced by a path directly.

Why is this bad?

Traits imported that aren’t used directly can be imported anonymously withuse Trait as _.It is more explicit, avoids polluting the current scope with unused names and can be useful to show which imports are required for traits.

Example

use std::fmt::Write;fn main() {    let mut s = String::new();    let _ = write!(s, "hello, world!");    println!("{s}");}

Use instead:

use std::fmt::Write as _;fn main() {    let mut s = String::new();    let _ = write!(s, "hello, world!");    println!("{s}");}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:1.83.0
Related Issues
View Source

unused_unit📋
stylewarn

What it does

Checks for unit (()) expressions that can be removed.

Why is this bad?

Such expressions add no value, but can make the codeless readable. Depending on formatting they can make abreak orreturnstatement look like a function call.

Example

fn return_unit() -> () {    ()}

is equivalent to

fn return_unit() {}
Applicability:MachineApplicable(?)
Added in:1.31.0
Related Issues
View Source

unusual_byte_groupings📋
stylewarn

What it does

Warns if hexadecimal or binary literals are not groupedby nibble or byte.

Why is this bad?

Negatively impacts readability.

Example

let x: u32 = 0xFFF_FFF;let y: u8 = 0b01_011_101;
Applicability:MaybeIncorrect(?)
Added in:1.49.0
Related Issues
View Source

unwrap_in_result📋
restrictionallow

What it does

Checks for functions of typeResult that containexpect() orunwrap()

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.

Example

Before:

fn divisible_by_3(i_str: String) -> Result<(), String> {    let i = i_str        .parse::<i32>()        .expect("cannot divide the input by three");    if i % 3 != 0 {        Err("Number is not divisible by 3")?    }    Ok(())}

After:

fn divisible_by_3(i_str: String) -> Result<(), String> {    let i = i_str        .parse::<i32>()        .map_err(|e| format!("cannot divide the input by three: {}", e))?;    if i % 3 != 0 {        Err("Number is not divisible by 3")?    }    Ok(())}
Applicability:Unspecified(?)
Added in:1.48.0
Related Issues
View Source

unwrap_or_default📋
stylewarn

What it does

Checks for usages of the following functions with an argument that constructs a default value(e.g.,Default::default orString::new):

  • unwrap_or
  • unwrap_or_else
  • or_insert
  • or_insert_with

Why is this bad?

Readability. Usingunwrap_or_default in place ofunwrap_or/unwrap_or_else, oror_defaultin place ofor_insert/or_insert_with, is simpler and more concise.

Known problems

In some cases, the argument ofunwrap_or, etc. is needed for type inference. The lint uses aheuristic to try to identify such cases. However, the heuristic can produce false negatives.

Examples

x.unwrap_or(Default::default());map.entry(42).or_insert_with(String::new);

Use instead:

x.unwrap_or_default();map.entry(42).or_default();

Past names

  • unwrap_or_else_default
Applicability:MachineApplicable(?)
Added in:1.56.0
Related Issues
View Source

unwrap_used📋
restrictionallow

What it does

Checks for.unwrap() or.unwrap_err() calls onResults and.unwrap() call onOptions.

Why restrict this?

It is better to handle theNone orErr case,or at least call.expect(_) with a more helpful message. Still, for a lot ofquick-and-dirty code,unwrap is a good choice, which is why this lint isAllow by default.

result.unwrap() will let the thread panic onErr values.Normally, you want to implement more sophisticated error handling,and propagate errors upwards with? operator.

Even if you want to panic on errors, not allErrors implement goodmessages on display. Therefore, it may be beneficial to look at the placeswhere they may get displayed. Activate this lint to do just that.

Examples

option.unwrap();result.unwrap();

Use instead:

option.expect("more helpful message");result.expect("more helpful message");

Ifexpect_used is enabled, instead:

option?;// orresult?;

Past names

  • option_unwrap_used
  • result_unwrap_used

Configuration

  • allow-unwrap-in-consts: Whetherunwrap should be allowed in code always evaluated at compile time

    (default:true)

  • allow-unwrap-in-tests: Whetherunwrap should be allowed in test functions or#[cfg(test)]

    (default:false)

Applicability:Unspecified(?)
Added in:1.45.0
Related Issues
View Source

upper_case_acronyms📋
stylewarn

What it does

Checks for fully capitalized names and optionally names containing a capitalized acronym.

Why is this bad?

In CamelCase, acronyms count as one word.Seenaming conventionsfor more.

By default, the lint only triggers on fully-capitalized names.You can use theupper-case-acronyms-aggressive: true config option to enable lintingon all camel case names

Known problems

When two acronyms are contiguous, the lint can’t tell wherethe first acronym ends and the second starts, so it suggests to lowercase all ofthe letters in the second acronym.

Example

struct HTTPResponse;

Use instead:

struct HttpResponse;

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

  • upper-case-acronyms-aggressive: Enables verbose mode. Triggers if there is more than one uppercase char next to each other

    (default:false)

Applicability:MaybeIncorrect(?)
Added in:1.51.0
Related Issues
View Source

use_debug📋
restrictionallow

What it does

Checks for usage ofDebug formatting. The purpose of thislint is to catch debugging remnants.

Why restrict this?

The purpose of theDebug trait is to facilitate debugging Rust code,andno guarantees are made about its output.It should not be used in user-facing output.

Example

println!("{:?}", foo);
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

use_self📋
nurseryallow

What it does

Checks for unnecessary repetition of structure name when areplacement withSelf is applicable.

Why is this bad?

Unnecessary repetition. Mixed use ofSelf and structnamefeels inconsistent.

Known problems

  • Unaddressed false negative in fn bodies of trait implementations

Example

struct Foo;impl Foo {    fn new() -> Foo {        Foo {}    }}

could be

struct Foo;impl Foo {    fn new() -> Self {        Self {}    }}

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

  • recursive-self-in-type-definitions: Whether the type itself in a struct or enum should be replaced withSelf when encountering recursive types.

    (default:true)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

used_underscore_binding📋
pedanticallow

What it does

Checks for the use of bindings with a single leadingunderscore.

Why is this bad?

A single leading underscore is usually used to indicatethat a binding will not be used. Using such a binding breaks thisexpectation.

Known problems

The lint does not work properly with desugaring andmacro, it has been allowed in the meantime.

Example

let _x = 0;let y = _x + 1; // Here we are using `_x`, even though it has a leading                // underscore. We should rename `_x` to `x`
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

used_underscore_items📋
pedanticallow

What it does

Checks for the use of item with a single leadingunderscore.

Why is this bad?

A single leading underscore is usually used to indicatethat a item will not be used. Using such a item breaks thisexpectation.

Example

fn _foo() {}struct _FooStruct {}fn main() {    _foo();    let _ = _FooStruct{};}

Use instead:

fn foo() {}struct FooStruct {}fn main() {    foo();    let _ = FooStruct{};}
Applicability:Unspecified(?)
Added in:1.83.0
Related Issues
View Source

useless_asref📋
complexitywarn

What it does

Checks for usage of.as_ref() or.as_mut() where thetypes before and after the call are the same.

Why is this bad?

The call is unnecessary.

Example

let x: &[i32] = &[1, 2, 3, 4, 5];do_stuff(x.as_ref());

The correct use would be:

let x: &[i32] = &[1, 2, 3, 4, 5];do_stuff(x);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

useless_attribute📋
correctnessdeny

What it does

Checks forextern crate anduse items annotated withlint attributes.

This lint permits lint attributes for lints emitted on the items themself.Foruse items these lints are:

  • ambiguous_glob_reexports
  • dead_code
  • deprecated
  • hidden_glob_reexports
  • unreachable_pub
  • unused
  • unused_braces
  • unused_import_braces
  • clippy::disallowed_types
  • clippy::enum_glob_use
  • clippy::macro_use_imports
  • clippy::module_name_repetitions
  • clippy::redundant_pub_crate
  • clippy::single_component_path_imports
  • clippy::unsafe_removed_from_name
  • clippy::wildcard_imports

Forextern crate items these lints are:

  • unused_imports on items with#[macro_use]

Why is this bad?

Lint attributes have no effect on crate imports. Mostlikely a! was forgotten.

Example

#[deny(dead_code)]extern crate foo;#[forbid(dead_code)]use foo::bar;

Use instead:

#[allow(unused_imports)]use foo::baz;#[allow(unused_imports)]#[macro_use]extern crate baz;
Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

useless_concat📋
complexitywarn

What it does

Checks that theconcat! macro has at least two arguments.

Why is this bad?

If there are less than 2 arguments, then calling the macro is doing nothing.

Example

let x = concat!("a");

Use instead:

let x = "a";
Applicability:MachineApplicable(?)
Added in:1.89.0
Related Issues
View Source

useless_conversion📋
complexitywarn

What it does

Checks forInto,TryInto,From,TryFrom, orIntoIter callswhich uselessly convert to the same type.

Why is this bad?

Redundant code.

Example

// format!() returns a `String`let s: String = format!("hello").into();

Use instead:

let s: String = format!("hello");

Past names

  • identity_conversion
Applicability:MachineApplicable(?)
Added in:1.45.0
Related Issues
View Source

useless_format📋
complexitywarn

What it does

Checks for the use offormat!("string literal with no argument") andformat!("{}", foo) wherefoo is a string.

Why is this bad?

There is no point of doing that.format!("foo") canbe replaced by"foo".to_owned() if you really need aString. The evenworse&format!("foo") is often encountered in the wild.format!("{}", foo) can be replaced byfoo.clone() iffoo: String orfoo.to_owned()iffoo: &str.

Examples

let foo = "foo";format!("{}", foo);

Use instead:

let foo = "foo";foo.to_owned();
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

useless_let_if_seq📋
nurseryallow

What it does

Checks for variable declarations immediately followed by aconditional affectation.

Why is this bad?

This is not idiomatic Rust.

Example

let foo;if bar() {    foo = 42;} else {    foo = 0;}let mut baz = None;if bar() {    baz = Some(42);}

should be written

let foo = if bar() {    42} else {    0};let baz = if bar() {    Some(42)} else {    None};
Applicability:HasPlaceholders(?)
Added in:pre 1.29.0
Related Issues
View Source

useless_nonzero_new_unchecked📋
complexitywarn

What it does

Checks forNonZero*::new_unchecked() being used in aconst context.

Why is this bad?

UsingNonZero*::new_unchecked() is anunsafe function and requires anunsafe context. When used in acontext evaluated at compilation time,NonZero*::new().unwrap() will provide the same result with identicalruntime performances while not requiringunsafe.

Example

use std::num::NonZeroUsize;const PLAYERS: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(3) };

Use instead:

use std::num::NonZeroUsize;const PLAYERS: NonZeroUsize = NonZeroUsize::new(3).unwrap();
Applicability:MachineApplicable(?)
Added in:1.86.0
Related Issues
View Source

useless_transmute📋
complexitywarn

What it does

Checks for transmutes to the original type of the objectand transmutes that could be a cast.

Why is this bad?

Readability. The code tricks people into thinking thatsomething complex is going on.

Example

core::intrinsics::transmute(t); // where the result type is the same as `t`'s
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

useless_vec📋
perfwarn

What it does

Checks for usage ofvec![..] when using[..] wouldbe possible.

Why is this bad?

This is less efficient.

Example

fn foo(_x: &[u8]) {}foo(&vec![1, 2]);

Use instead:

foo(&[1, 2]);

Configuration

  • allow-useless-vec-in-tests: Whetheruseless_vec should ignore test functions or#[cfg(test)]

    (default:false)

  • too-large-for-stack: The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap

    (default:200)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

vec_box📋
complexitywarn

What it does

Checks for usage ofVec<Box<T>> where T: Sized anywhere in the code.Check theBox documentation for more information.

Why is this bad?

Vec already keeps its contents in a separate area onthe heap. So if youBox its contents, you just add another level of indirection.

Example

struct X {    values: Vec<Box<i32>>,}

Better:

struct X {    values: Vec<i32>,}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

  • vec-box-size-threshold: The size of the boxed type in bytes, where boxing in aVec is allowed

    (default:4096)

Applicability:Unspecified(?)
Added in:1.33.0
Related Issues
View Source

vec_init_then_push📋
perfwarn

What it does

Checks for calls topush immediately after creating a newVec.

If theVec is created usingwith_capacity this will only lint if the capacity is aconstant and the number of pushes is greater than or equal to the initial capacity.

If theVec is extended after the initial sequence of pushes and it was default initializedthen this will only lint after there were at least four pushes. This number may change inthe future.

Why is this bad?

Thevec![] macro is both more performant and easier to read thanmultiplepush calls.

Example

let mut v = Vec::new();v.push(0);v.push(1);v.push(2);

Use instead:

let v = vec![0, 1, 2];
Applicability:HasPlaceholders(?)
Added in:1.51.0
Related Issues
View Source

vec_resize_to_zero📋
correctnessdeny

What it does

Finds occurrences ofVec::resize(0, an_int)

Why is this bad?

This is probably an argument inversion mistake.

Example

vec![1, 2, 3, 4, 5].resize(0, 5)

Use instead:

vec![1, 2, 3, 4, 5].clear()
Applicability:MaybeIncorrect(?)
Added in:1.46.0
Related Issues
View Source

verbose_bit_mask📋
pedanticallow

What it does

Checks for bit masks that can be replaced by a calltotrailing_zeros

Why is this bad?

x.trailing_zeros() >= 4 is much clearer thanx & 15 == 0

Example

if x & 0b1111 == 0 { }

Use instead:

if x.trailing_zeros() >= 4 { }

Configuration

  • verbose-bit-mask-threshold: The maximum allowed size of a bit mask before suggesting to use ‘trailing_zeros’

    (default:1)

Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

verbose_file_reads📋
restrictionallow

What it does

Checks for usage of File::read_to_end and File::read_to_string.

Why restrict this?

fs::{read, read_to_string} provide the same functionality whenbuf is empty with fewer imports and no intermediate values.See also:fs::read docs,fs::read_to_string docs

Example

let mut f = File::open("foo.txt").unwrap();let mut bytes = Vec::new();f.read_to_end(&mut bytes).unwrap();

Can be written more concisely as

let mut bytes = fs::read("foo.txt").unwrap();
Applicability:Unspecified(?)
Added in:1.44.0
Related Issues
View Source

volatile_composites📋
nurseryallow

What it does

This lint warns when volatile load/store operations(write_volatile/read_volatile) are applied to composite types.

Why is this bad?

Volatile operations are typically used with memory mapped IO devices,where the precise number and ordering of load and store instructions isimportant because they can have side effects. This is well defined forprimitive types likeu32, but less well defined for structures andother composite types. In practice it’s implementation defined, and thebehavior can be rustc-version dependent.

As a result, code should only applywrite_volatile/read_volatile toprimitive types to be fully well-defined.

Example

struct MyDevice {    addr: usize,    count: usize}fn start_device(device: *mut MyDevice, addr: usize, count: usize) {    unsafe {        device.write_volatile(MyDevice { addr, count });    }}

Instead, operate on each primtive field individually:

struct MyDevice {    addr: usize,    count: usize}fn start_device(device: *mut MyDevice, addr: usize, count: usize) {    unsafe {        (&raw mut (*device).addr).write_volatile(addr);        (&raw mut (*device).count).write_volatile(count);    }}
Applicability:Unspecified(?)
Added in:1.92.0
Related Issues
View Source

waker_clone_wake📋
perfwarn

What it does

Checks for usage ofwaker.clone().wake()

Why is this bad?

Cloning the waker is not necessary,wake_by_ref() enables the same operationwithout extra cloning/dropping.

Example

waker.clone().wake();

Should be written

waker.wake_by_ref();
Applicability:MachineApplicable(?)
Added in:1.75.0
Related Issues
View Source

while_float📋
nurseryallow

What it does

Checks for while loops comparing floating point values.

Why is this bad?

If you increment floating point values, errors can compound,so, use integers instead if possible.

Known problems

The lint will catch all while loops comparing floating pointvalues without regarding the increment.

Example

let mut x = 0.0;while x < 42.0 {    x += 1.0;}

Use instead:

let mut x = 0;while x < 42 {    x += 1;}
Applicability:Unspecified(?)
Added in:1.80.0
Related Issues
View Source

while_immutable_condition📋
correctnessdeny

What it does

Checks whether variables used within while loop conditioncan be (and are) mutated in the body.

Why is this bad?

If the condition is unchanged, entering the body of the loopwill lead to an infinite loop.

Known problems

If thewhile-loop is in a closure, the check for mutation of thecondition variables in the body can cause false negatives. For example when onlyUpvara isin the condition and onlyUpvarb gets mutated in the body, the lint will not trigger.

Example

let i = 0;while i > 10 {    println!("let me loop forever!");}
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

while_let_loop📋
complexitywarn

What it does

Detectsloop + match combinations that are easierwritten as awhile let loop.

Why is this bad?

Thewhile let loop is usually shorter and morereadable.

Example

let y = Some(1);loop {    let x = match y {        Some(x) => x,        None => break,    };    // ..}

Use instead:

let y = Some(1);while let Some(x) = y {    // ..};
Applicability:HasPlaceholders(?)
Added in:pre 1.29.0
Related Issues
View Source

while_let_on_iterator📋
stylewarn

What it does

Checks forwhile let expressions on iterators.

Why is this bad?

Readability. A simplefor loop is shorter and conveysthe intent better.

Example

while let Some(val) = iter.next() {    ..}

Use instead:

for val in &mut iter {    ..}
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

wildcard_dependencies📋
cargoallow

What it does

Checks for wildcard dependencies in theCargo.toml.

Why is this bad?

As the edition guide says,it is highly unlikely that you work with any possible version of your dependency,and wildcard dependencies would cause unnecessary breakage in the ecosystem.

Example

[dependencies]regex = "*"

Use instead:

[dependencies]some_crate_1 = "~1.2.3"some_crate_2 = "=1.2.3"
Applicability:Unspecified(?)
Added in:1.32.0
Related Issues
View Source

wildcard_enum_match_arm📋
restrictionallow

What it does

Checks for wildcard enum matches using_.

Why restrict this?

New enum variants added by library updates can be missed.

Known problems

Suggested replacements may be incorrect if guards exhaustively cover somevariants, and also may not use correct path to enum if it’s not present in the current scope.

Example

match x {    Foo::A(_) => {},    _ => {},}

Use instead:

match x {    Foo::A(_) => {},    Foo::B(_) => {},}
Applicability:MaybeIncorrect(?)
Added in:1.34.0
Related Issues
View Source

wildcard_imports📋
pedanticallow

What it does

Checks for wildcard importsuse _::*.

Why is this bad?

wildcard imports can pollute the namespace. This is especially bad ifyou try to import something through a wildcard, that already has been imported by name froma different source:

use crate1::foo; // Imports a function named foouse crate2::*; // Has a function named foofoo(); // Calls crate1::foo

This can lead to confusing error messages at best and to unexpected behavior at worst.

Exceptions

Wildcard imports are allowed from modules that their name containsprelude. Many crates(including the standard library) provide modules named “prelude” specifically designedfor wildcard import.

Wildcard imports reexported throughpub use are also allowed.

use super::* is allowed in test modules. This is defined as any module with “test” in the name.

These exceptions can be disabled using thewarn-on-all-wildcard-imports configuration flag.

Known problems

If macros are imported through the wildcard, this macro is not includedby the suggestion and has to be added by hand.

Applying the suggestion when explicit imports of the things imported with a glob importexist, may result inunused_imports warnings.

Example

use crate1::*;foo();

Use instead:

use crate1::foo;foo();

Configuration

  • allowed-wildcard-imports: List of path segments allowed to have wildcard imports.

Example

allowed-wildcard-imports = [ "utils", "common" ]

Noteworthy

  1. This configuration has no effects if used withwarn_on_all_wildcard_imports = true.
  2. Paths with any segment that containing the word ‘prelude’are already allowed by default.

(default:[])

  • warn-on-all-wildcard-imports: Whether to emit warnings on all wildcard imports, including those fromprelude, fromsuper in tests,or forpub use reexports.

    (default:false)

Applicability:MachineApplicable(?)
Added in:1.43.0
Related Issues
View Source

wildcard_in_or_patterns📋
complexitywarn

What it does

Checks for wildcard pattern used with others patterns in same match arm.

Why is this bad?

Wildcard pattern already covers any other pattern as it will match anyway.It makes the code less readable, especially to spot wildcard pattern use in match arm.

Example

match s {    "a" => {},    "bar" | _ => {},}

Use instead:

match s {    "a" => {},    _ => {},}
Applicability:Unspecified(?)
Added in:1.42.0
Related Issues
View Source

write_literal📋
stylewarn

What it does

This lint warns about the use of literals aswrite!/writeln! args.

Why is this bad?

Using literals aswriteln! args is inefficient(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary(i.e., just put the literal in the format string)

Example

writeln!(buf, "{}", "foo");

Use instead:

writeln!(buf, "foo");
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

write_with_newline📋
stylewarn

What it does

This lint warns when you usewrite!() with a formatstring thatends in a newline.

Why is this bad?

You should usewriteln!() instead, which appends thenewline.

Example

write!(buf, "Hello {}!\n", name);

Use instead:

writeln!(buf, "Hello {}!", name);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

writeln_empty_string📋
stylewarn

What it does

This lint warns when you usewriteln!(buf, "") toprint a newline.

Why is this bad?

You should usewriteln!(buf), which is simpler.

Example

writeln!(buf, "");

Use instead:

writeln!(buf);
Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

wrong_pub_self_convention📋
deprecatednone

What it does

Nothing. This lint has been deprecated

Deprecation reason

clippy::wrong_self_convention now covers this case via theavoid-breaking-exported-api config.

Applicability:Unspecified(?)
Deprecated in:1.54.0
Related Issues

wrong_self_convention📋
stylewarn

What it does

Checks for methods with certain name prefixes or suffixes, and whichdo not adhere to standard conventions regarding howself is taken.The actual rules are:

PrefixPostfixself takenself type
as_none&self or&mut selfany
from_nonenoneany
into_noneselfany
is_none&mut self or&self or noneany
to__mut&mut selfany
to_not_mutselfCopy
to_not_mut&selfnotCopy

Note: Clippy doesn’t trigger methods withto_ prefix in:

  • Traits definition.Clippy can not tell if a type that implements a trait isCopy or not.
  • Traits implementation, when&self is taken.The method signature is controlled by the trait and often&self is required for all types that implement the trait(see e.g. thestd::string::ToString trait).

Clippy allowsPin<&Self> andPin<&mut Self> if&self and&mut self is required.

Please find more info here:https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv

Why is this bad?

Consistency breeds readability. If you follow theconventions, your users won’t be surprised that they, e.g., need to supply amutable reference to aas_.. function.

Example

impl X {    fn as_str(self) -> &'static str {        // ..    }}

Use instead:

impl X {    fn as_str(&self) -> &'static str {        // ..    }}

Configuration

  • avoid-breaking-exported-api: Suppress lints whenever the suggested change would cause breakage for other crates.

    (default:true)

Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

wrong_transmute📋
correctnessdeny

What it does

Checks for transmutes that can’t ever be correct on anyarchitecture.

Why is this bad?

It’s basically guaranteed to be undefined behavior.

Known problems

When accessing C, users might want to store pointersized objects inextradata arguments to save an allocation.

Example

let ptr: *const T = core::intrinsics::transmute('x')
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

zero_divided_by_zero📋
complexitywarn

What it does

Checks for0.0 / 0.0.

Why is this bad?

It’s less readable thanf32::NAN orf64::NAN.

Example

let nan = 0.0f32 / 0.0;

Use instead:

let nan = f32::NAN;
Applicability:Unspecified(?)
Added in:pre 1.29.0
Related Issues
View Source

zero_prefixed_literal📋
complexitywarn

What it does

Warns if an integral constant literal starts with0.

Why is this bad?

In some languages (including the infamous C languageand most of itsfamily), this marks an octal constant. In Rust however, this is a decimalconstant. This couldbe confusing for both the writer and a reader of the constant.

Example

In Rust:

fn main() {    let a = 0123;    println!("{}", a);}

prints123, while in C:

#include <stdio.h>int main() {    int a = 0123;    printf("%d\n", a);}

prints83 (as83 == 0o123 while123 == 0o173).

Applicability:MaybeIncorrect(?)
Added in:pre 1.29.0
Related Issues
View Source

zero_ptr📋
stylewarn

What it does

Catch casts from0 to some pointer type

Why is this bad?

This generally meansnull and is better expressed as{std,core}::ptr::{null,null_mut}.

Example

let a = 0 as *const u32;

Use instead:

let a = std::ptr::null::<u32>();

Configuration

  • msrv: The minimum rust version that the project supports. Defaults to therust-version field inCargo.toml

    (default:current version)

Applicability:MachineApplicable(?)
Added in:pre 1.29.0
Related Issues
View Source

zero_repeat_side_effects📋
suspiciouswarn

What it does

Checks for array or vec initializations which contain an expression with side effects,but which have a repeat count of zero.

Why is this bad?

Such an initialization, despite having a repeat length of 0, will still call the inner function.This may not be obvious and as such there may be unintended side effects in code.

Example

fn side_effect() -> i32 {    println!("side effect");    10}let a = [side_effect(); 0];

Use instead:

fn side_effect() -> i32 {    println!("side effect");    10}side_effect();let a: [i32; 0] = [];
Applicability:Unspecified(?)
Added in:1.79.0
Related Issues
View Source

zero_sized_map_values📋
pedanticallow

What it does

Checks for maps with zero-sized value types anywhere in the code.

Why is this bad?

Since there is only a single value for a zero-sized type, a mapcontaining zero sized values is effectively a set. Using a set in that case improvesreadability and communicates intent more clearly.

Known problems

  • A zero-sized type cannot be recovered later if it contains private fields.
  • This lints the signature of public items

Example

fn unique_words(text: &str) -> HashMap<&str, ()> {    todo!();}

Use instead:

fn unique_words(text: &str) -> HashSet<&str> {    todo!();}
Applicability:Unspecified(?)
Added in:1.50.0
Related Issues
View Source

zombie_processes📋
suspiciouswarn

What it does

Looks for code that spawns a process but never callswait() on the child.

Why is this bad?

As explained in thestandard library documentation,callingwait() is necessary on Unix platforms to properly release all OS resources associated with the process.Not doing so will effectively leak process IDs and/or other limited global resources,which can eventually lead to resource exhaustion, so it’s recommended to callwait() in long-running applications.Such processes are called “zombie processes”.

To reduce the rate of false positives, if the spawned process is assigned to a binding, the lint actually works the other way around; itconservatively checks that all uses of a variable definitely don’t callwait() and only then emits a warning.For that reason, a seemingly unrelated use can get called out as callingwait() in help messages.

Control flow

If await() call exists in an if/then block but not in the else block (or there is no else block),then this still gets linted as not callingwait() in all code paths.Likewise, when early-returning from the function,wait() calls that appear after the return expressionare also not accepted.In other words, thewait() call must be unconditionally reachable after the spawn expression.

Example

use std::process::Command;let _child = Command::new("ls").spawn().expect("failed to execute child");

Use instead:

use std::process::Command;let mut child = Command::new("ls").spawn().expect("failed to execute child");child.wait().expect("failed to wait on child");
Applicability:MaybeIncorrect(?)
Added in:1.83.0
Related Issues
View Source

zst_offset📋
correctnessdeny

What it does

Checks foroffset(_),wrapping_{add,sub}, etc. on raw pointers tozero-sized types

Why is this bad?

This is a no-op, and likely unintended

Example

unsafe { (&() as *const ()).offset(1) };
Applicability:Unspecified(?)
Added in:1.41.0
Related Issues
View Source

[8]ページ先頭

©2009-2025 Movatter.jp