63 KiB
- Feature Name:
clippy_uno
- Start Date: 2018-06-14
- RFC PR: rust-lang/rfcs#2476
- Rust Issue: rust-lang-nursery/rust-clippy#3343
Summary
Release Clippy 1.0, in preparation for it being shipped via rustup and eventually available via Rust Stable.
Motivation
See also: The Future of Clippy
Clippy, the linter for Rust, has been a nightly-only plugin to Rust for many years. In that time, it's grown big, but it's nightly-only nature makes it pretty hard to use.
The eventual plan is to integrate it in Rustup à la Rustfmt/RLS so that you can simply fetch prebuilt binaries
for your system and cargo clippy
Just Works ™️. In preparation for this, we'd like to nail down various things
about its lints and their categorization.
Guide-level explanation
Usage and lint philosophy
We expect Clippy to be used via cargo clippy
.
Clippy aims to follow the general Rust style. It may be somewhat opiniated in some situations.
In general Clippy is intended to be used with a liberal sprinkling of #[allow()]
and #[warn()]
; it is okay to
disagree with Clippy's choices. This is a weaker philosophy than that behind rustc's lints, where usually flipping
one is an indication of a very specialized situation.
Lint attributes
Currently to allow/deny Clippy lints you have to #[cfg_attr(clippy, allow(lintname))]
which is somewhat tedious.
The compiler should support something like #[allow(clippy::lintname)]
which won't attempt to warn about nonexistent lints
at all when not running Clippy.
Stability guarantees
Clippy will have the same idea of lint stability as rustc; essentially we do not guarantee stability under #[deny(lintname)]
.
This is not a problem since deny only affects the current crate (dependencies have their lints capped)
so at most you’ll be forced to slap on an #[allow()]
for your own crate following a Rust upgrade.
This means that we will never remove lints. We may recategorize lints, and we may "deprecate" them. Deprecation "removes" them by removing their functionality and marking them as deprecated, which may cause further warnings but cannot cause a compiler error.
It also means that we won't make fundamentally large changes to lints. You can expect that turning on a lint will keep it behaving mostly similarly over time, unless it is removed. The kinds of changes we will make are:
- Adding entirely new lints
- Fixing false positives (A lint may no longer lint in a buggy case)
- Fixing false negatives (A case where the lint should be linting but doesn’t is fixed)
- Bugfixes (When the lint panics or does something otherwise totally broken)
When fixing false negatives this will usually be fixing things that can be
understood as comfortably within the scope of the lint as documented/named.
For example, a lint on having the type Box<Vec<_>>
may be changed to also catch Box<Vec<T>>
where T
is generic, but will not be changed to also catch Box<String>
(which can be linted
on for the same reasons).
An exception to this is the "nursery" lints — Clippy has a lint category for unpolished lints called the "nursery" which are allow-by-default. These may experience radical changes, however they will never be entirely "removed" either.
Pre-1.0 we may also flush out all of the deprecated lints.
The configuration file for clippy, clippy.toml, is not stabilized in this RFC. Instead, we propose to require clippy.toml users set a clippy_toml_is_unstable_and_may_go_away
option.
The interface and existence of cargo-clippy
is also not stabilized in this RFC. We will continue shipping it with rustup, but it may be replaced in the future with a combined cargo lint
command.
Lint audit and categories
A couple months ago we did a lint audit to recategorize all the Clippy lints. The Reference-Level explanation below contains a list of all of these lints as currently categorized.
The categories we came up with are:
- Correctness (Deny): Probable bugs, e.g. calling
.clone()
on&&T
, which clones the (Copy
) reference and not the actual type - Style (Warn): Style issues; where the fix usually doesn't semantically change the code but instead changes naming/formatting.
For example, having a method named
into_foo()
that doesn't takeself
by-move - Complexity (Warn): For detecting unnecessary code complexities and helping
simplify them. For example, a lint that asks you to replace
.filter(..).next()
with.find(..)
- Perf (Warn): Detecting potential performance footguns, like using
Box<Vec<T>>
or calling.or(foo())
instead ofor_else(foo)
. - Pedantic (Allow): Controversial or exceedingly pedantic lints
- Nursery (Allow): For lints which are buggy or need more work
- Cargo (Allow): Lints about your Cargo setup
- Restriction (Allow): Lints for things which are not usually a problem, but may be something specific situations may dictate disallowing.
- Internal (Allow): Nothing to see here, move along
- Deprecated (Allow): Empty lints that exist to ensure that
#[allow(lintname)]
still compiles after the lint was deprecated.
Lints can only belong to one lint group at a time, and the lint group defines the lint level. There is a bunch of overlap between the style and complexity groups -- a lot of style issues are also complexity issues and vice versa. We separate these groups so that people can opt in to the complexity lints without having to opt in to Clippy's style.
Compiler uplift
The compiler has historically had a "no new lints" policy, partly with the desire that lints would incubate outside of the compiler (so usually in Clippy). This feels like a good time to look into uplifting these lints.
This RFC does not yet propose lints to be uplifted, but the intention is that the RFC discussion will bring up lints that the community feels should be uplifted and we can list them here.
Such an uplift may change the lint level; correctness lints are Deny by default in Clippy but would probably switch to Warn if uplifted since the compiler is more conservative here (Using Clippy is in itself an opt-in to a "please annoy me more" mode).
We'd also like to establish a rough policy for future lints here: Some correctness lints should probably belong in the compiler, whereas style/complexity/etc lints should probably belong in Clippy. Lints may be incubated in Clippy, of course.
I don't think the compler will want all correctness lints here, however if the lint is about a common enough situation where it being not a bug is an exceedingly rare case (i.e. very low false positive frequency) it should probably belong in the compiler.
What lints belong in clippy?
Essentially, we consider the categorization itself to be a definition of boundaries -- if it doesn't fit in the categories, it doesn't fit in clippy (or needs an RFC for, specifically).
In itself this isn't complete, we explicitly have a "pedantic" group that's kinda ill defined.
The rules for the main categories (style/complexity/correctness/perf -- things which are warn or deny by default) are:
- Main category lints need to be something the community has general agreement on. This does not mean each lint addition must go through an RFC-like process. Instead, this is to be judged by the maintainers during the review of the lint pull request (taking into account objections raised if any). If the lint turns out to be controversial in the future we can flip it off or recategorize it.
- Generally, if a lint is triggered, this should be useful to most Rust programmers seeing it most of the time.
- It is okay for a lint to deal with niche code that usually won't even be triggered. Lints can target subsets of the community provided they don't randomly trigger for others.
- It is okay if the lint has some false positives (cases where it lints for things which are actually okay), as long as they don't dominate.
- It is also okay if the lint warns about things which people do not feel are worth fixing -- i.e. the programmer agrees that it is a problem but does not wish to fix this. Using clippy is itself an opt-in to more finicky linting. However, this is sometimes an indicator of such a lint potentially belonging in the pedantic group.
- Clippy is meant to be used with a liberal sprinkling of
allow
. If there's a specific use case where a lint doesn't apply, and the solution is to slapallow
on it, that's okay. A minor level of false positives like this is to be tolerated. Similarly, style lints are allowed to be about things a lot of people don't care about (i.e. they don't prefer the opposite style, they just don't care). - Clippy lints do deal with the visual presentation of your code, but only for things which
rustfmt
doesn't or can't handle. So, for example, rustfmt will not ask you to replaceif {} else { if {} }
withif {} else if {}
, but clippy might. There is some overlap in this area and we expect to work with rustfmt on precisely figuring out what goes where. Such lints are usuallystyle
lints orcomplexity
lints. - Clippy lints are allowed to make some kind of semantic changes, but not all:
- The general rule is that clippy will not attempt to change what it perceives to be the intent of the code, but will rather change the code to make it closer to the intent or make it achieve that intent better
- Clippy lints do deal with potential typos and mistakes. For example, clippy will detect
for x in y.next()
which is very likely a bug (you either meanif let
or mean to unwrap). Such lints are usuallycorrectness
lints. - Clippy lints also do deal with misunderstandings of Rust, for example code doing
foo == NaN
is a misunderstanding of how Rust floats work. These are also usuallycorrectness
lints. - Clippy lints do not comment on the business logic of your program. This comes from the "perceived intent" rule above, changes to business logic are a change to perceived intent.
- Clippy lints do ask you to make semantic changes that achieve the same effect with
perhaps better performance. Such lints are usually
perf
lints.
For the other categories (these are allow by default):
- Lints which are "pedantic" should still roughly fall into one of the main categories, just that they are too annoying (or possibly controversial) to be warn by default. So a lint must follow all the above rules if pedantic, but is allowed to be "too finicky to fix", and may have looser consensus (i.e. some controversy).
- Similar rules for "nursery" except their reason for being allow by default is lack of maturity (i.e. the lint is buggy or still needs some thought)
- "restriction" lints follow all the rules for semantic changes, but do not bother with the rules for the lint being useful to most rust programmers. A restriction lint must still be such that you have a good reason to enable it — "I dislike such code" is insufficient — but will likely be a lint most programmers wish to keep off by default for most of their code. The goal of restriction lints is to provide tools with which you can supplement the language checks in very specific cases where you need it, e.g. forbidding panics from a certain area of code.
- "cargo" lints follow the same rules as pedantic lints (we only have one of them right now, so we may be experimenting with this in the future)
Reference-level explanation
Lint categorization
This categorization can be browsed online.
Please leave comments on thoughts about these lints -- if their categorization is correct, if they should exist at all, and if we should be uplifting them to the compiler.
For ease of review, the lints below are as they were listed in the original RFC. The proposed changes are:
shadow_unrelated
be moved fromrestriction
topedantic
- Various lints be uplifted to the compiler (and potentially renamed). This is tracked in https://github.com/rust-lang/rust/issues/53224
explicit_iter_loop
andexplicit_into_iter_loop
be moved fromstyle
topedantic
correctness (Deny)
- for_loop_over_option: Checks for
for
loops overOption
values. - eq_op: Checks for equal operands to comparison, logical and
bitwise, difference and division binary operators (
==
,>
, etc.,&&
,||
,&
,|
,^
,-
and/
). - iter_next_loop: Checks for loops on
x.next()
. - deprecated_semver: Checks for
#[deprecated]
annotations with asince
field that is not a valid semantic version. - drop_copy: Checks for calls to
std::mem::drop
with a value that derives the Copy trait - not_unsafe_ptr_arg_deref: Checks for public functions that dereferences raw pointer arguments but are not marked unsafe.
- logic_bug: Checks for boolean expressions that contain terminals that can be eliminated.
- clone_double_ref: Checks for usage of
.clone()
on an&&T
. - almost_swapped: Checks for
foo = bar; bar = foo
sequences. - possible_missing_comma: Checks for possible missing comma in an array. It lints if an array element is a binary operator expression and it lies on two lines.
- wrong_transmute: Checks for transmutes that can't ever be correct on any architecture.
- invalid_regex: Checks regex creation
(with
Regex::new
,RegexBuilder::new
orRegexSet::new
) for correct regex syntax. - bad_bit_mask: Checks for incompatible bit masks in comparisons.
- drop_ref: Checks for calls to
std::mem::drop
with a reference instead of an owned value. - derive_hash_xor_eq: Checks for deriving
Hash
but implementingPartialEq
explicitly or vice versa. - useless_attribute: Checks for
extern crate
anduse
items annotated with lint attributes - temporary_cstring_as_ptr: Checks for getting the inner pointer of a temporary
CString
. - min_max: Checks for expressions where
std::cmp::min
andmax
are used to clamp values, but switched so that the result is constant. - unit_cmp: Checks for comparisons to unit.
- reverse_range_loop: Checks for loops over ranges
x..y
where bothx
andy
are constant andx
is greater or equal toy
, unless the range is reversed or has a negative.step_by(_)
. - erasing_op: Checks for erasing operations, e.g.
x * 0
. - suspicious_op_assign_impl: Lints for suspicious operations in impls of OpAssign, e.g. subtracting elements in an AddAssign impl.
- float_cmp: Checks for (in-)equality comparisons on floating-point
values (apart from zero), except in functions called
*eq*
(which probably implement equality for a type involving floats). - zero_width_space: Checks for the Unicode zero-width space in the code.
- fn_to_numeric_cast_with_truncation: Checks for casts of a function pointer to a numeric type not enough to store address.
- suspicious_arithmetic_impl: Lints for suspicious operations in impls of arithmetic operators, e.g. subtracting elements in an Add impl.
- approx_constant: Checks for floating point literals that approximate
constants which are defined in
std::f32::consts
orstd::f64::consts
, respectively, suggesting to use the predefined constant. - while_immutable_condition: Checks whether variables used within while loop condition can be (and are) mutated in the body.
- never_loop: Checks for loops that will always
break
,return
orcontinue
an outer loop. - nonsensical_open_options: Checks for duplicate open options as well as combinations that make no sense.
- forget_copy: Checks for calls to
std::mem::forget
with a value that derives the Copy trait - if_same_then_else: Checks for
if/else
with the same body as the then part and the else part. - cast_ptr_alignment: Checks for casts from a less-strictly-aligned pointer to a more-strictly-aligned pointer
- ifs_same_cond: Checks for consecutive
if
s with the same condition. - out_of_bounds_indexing: Checks for out of bounds array indexing with a constant index.
- modulo_one: Checks for getting the remainder of a division by one.
- inline_fn_without_body: Checks for
#[inline]
on trait methods without bodies - cmp_nan: Checks for comparisons to NaN.
- ineffective_bit_mask: Checks for bit masks in comparisons which can be removed without changing the outcome.
- infinite_iter: Checks for iteration that is guaranteed to be infinite.
- mut_from_ref: This lint checks for functions that take immutable references and return mutable ones.
- unused_io_amount: Checks for unused written/read amount.
- invalid_ref: Checks for creation of references to zeroed or uninitialized memory.
- serde_api_misuse: Checks for mis-uses of the serde API.
- forget_ref: Checks for calls to
std::mem::forget
with a reference instead of an owned value. - absurd_extreme_comparisons: Checks for comparisons where one side of the relation is either the minimum or maximum value for its type and warns if it involves a case that is always true or always false. Only integer and boolean types are checked.
- for_loop_over_result: Checks for
for
loops overResult
values. - iterator_step_by_zero: Checks for calling
.step_by(0)
on iterators, which never terminates. - enum_clike_unportable_variant: Checks for C-like enumerations that are
repr(isize/usize)
and have values that don't fit into ani32
.
style (Warn)
- inconsistent_digit_grouping: Warns if an integral or floating-point constant is grouped inconsistently with underscores.
- get_unwrap: Checks for use of
.get().unwrap()
(or.get_mut().unwrap
) on a standard library type which implementsIndex
- match_bool: Checks for matches where match expression is a
bool
. It suggests to replace the expression with anif...else
block. - cmp_null: This lint checks for equality comparisons with
ptr::null
- write_with_newline: This lint warns when you use
write!()
with a format string that ends in a newline. - unneeded_field_pattern: Checks for structure field patterns bound to wildcards.
- new_without_default_derive: Checks for types with a
fn new() -> Self
method and no implementation ofDefault
, where theDefault
can be derived by#[derive(Default)]
. - zero_ptr: Catch casts from
0
to some pointer type - wrong_self_convention: Checks for methods with certain name prefixes and which doesn't match how self is taken.
- iter_skip_next: Checks for use of
.skip(x).next()
on iterators. - large_digit_groups: Warns if the digits of an integral or floating-point constant are grouped into groups that are too large.
- range_minus_one: Checks for inclusive ranges where 1 is subtracted from
the upper bound, e.g.
x..=(y-1)
. - regex_macro: Checks for usage of
regex!(_)
which (as of now) is usually slower thanRegex::new(_)
unless called in a loop (which is a bad idea anyway). - op_ref: Checks for arguments to
==
which have their address taken to satisfy a bound and suggests to dereference the other argument instead - question_mark: Checks for expressions that could be replaced by the question mark operator
- redundant_closure: Checks for closures which just call another function where
the function can be called directly.
unsafe
functions or calls where types get adjusted are ignored. - print_with_newline: This lint warns when you use
print!()
with a format string that ends in a newline. - match_ref_pats: Checks for matches where all arms match a reference,
suggesting to remove the reference and deref the matched expression
instead. It also checks for
if let &foo = bar
blocks. - ptr_arg: This lint checks for function arguments of type
&String
or&Vec
unless the references are mutable. It will also suggest you replace.clone()
calls with the appropriate.to_owned()
/to_string()
calls. - chars_last_cmp: Checks for usage of
.chars().last()
or.chars().next_back()
on astr
to check if it ends with a given char. - assign_op_pattern: Checks for
a = a op b
ora = b commutative_op a
patterns. - mixed_case_hex_literals: Warns on hexadecimal literals with mixed-case letter digits.
- blacklisted_name: Checks for usage of blacklisted names for variables, such
as
foo
. - double_neg: Detects expressions of the form
--x
. - unnecessary_fold: Checks for using
fold
when a more succinct alternative exists. Specifically, this checks forfold
s which could be replaced byany
,all
,sum
orproduct
. - let_unit_value: Checks for binding a unit value.
- needless_range_loop: Checks for looping over the range of
0..len
of some collection just to get the values by index. - excessive_precision: Checks for float literals with a precision greater than that supported by the underlying type
- duplicate_underscore_argument: Checks for function arguments having the similar names differing by an underscore.
- println_empty_string: This lint warns when you use
println!("")
to print a newline. - panic_params: Checks for missing parameters in
panic!
. - writeln_empty_string: This lint warns when you use
writeln!(buf, "")
to print a newline. - infallible_destructuring_match: Checks for matches being used to destructure a single-variant enum
or tuple struct where a
let
will suffice. - block_in_if_condition_stmt: Checks for
if
conditions that use blocks containing statements, or conditions that use closures with blocks. - unreadable_literal: Warns if a long integral or floating-point constant does not contain underscores.
- unsafe_removed_from_name: Checks for imports that remove "unsafe" from an item's name.
- builtin_type_shadow: Warns if a generic shadows a built-in type.
- option_map_or_none: Checks for usage of
_.map_or(None, _)
. - neg_multiply: Checks for multiplication by -1 as a form of negation.
- const_static_lifetime: Checks for constants with an explicit
'static
lifetime. - explicit_iter_loop: Checks for loops on
x.iter()
where&x
will do, and suggests the latter. - single_match: Checks for matches with a single arm where an
if let
will usually suffice. - for_kv_map: Checks for iterating a map (
HashMap
orBTreeMap
) and ignoring either the keys or values. - if_let_some_result: * Checks for unnecessary
ok()
in if let. - collapsible_if: Checks for nested
if
statements which can be collapsed by&&
-combining their conditions and forelse { if ... }
expressions that can be collapsed toelse if ...
. - len_without_is_empty: Checks for items that implement
.len()
but not.is_empty()
. - unnecessary_mut_passed: Detects giving a mutable reference to a function that only requires an immutable reference.
- useless_let_if_seq: Checks for variable declarations immediately followed by a conditional affectation.
- new_ret_no_self: Checks for
new
not returningSelf
. - write_literal: This lint warns about the use of literals as
write!
/writeln!
args. - block_in_if_condition_expr: Checks for
if
conditions that use blocks to contain an expression. - toplevel_ref_arg: Checks for function arguments and let bindings denoted as
ref
. - suspicious_else_formatting: Checks for formatting of
else if
. It lints if theelse
andif
are not on the same line or theelse
seems to be missing. - fn_to_numeric_cast: Checks for casts of a function pointer to a numeric type except
usize
. - let_and_return: Checks for
let
-bindings, which are subsequently returned. - len_zero: Checks for getting the length of something via
.len()
just to compare to zero, and suggests using.is_empty()
where applicable. - suspicious_assignment_formatting: Checks for use of the non-existent
=*
,=!
and=-
operators. - redundant_field_names: Checks for fields in struct literals where shorthands could be used.
- string_lit_as_bytes: Checks for the
as_bytes
method called on string literals that contain only ASCII characters. - verbose_bit_mask: Checks for bit masks that can be replaced by a call
to
trailing_zeros
- map_clone: Checks for mapping
clone()
over an iterator. - new_without_default: Checks for types with a
fn new() -> Self
method and no implementation ofDefault
. - should_implement_trait: Checks for methods that should live in a trait
implementation of a
std
trait (see llogiq's blog post for further information) instead of an inherent implementation. - match_wild_err_arm: Checks for arm which matches all errors with
Err(_)
and take drastic actions likepanic!
. - iter_cloned_collect: Checks for the use of
.cloned().collect()
on slice to create aVec
. - module_inception: Checks for modules that have the same name as their parent module
- many_single_char_names: Checks for too many variables whose name consists of a single character.
- enum_variant_names: Detects enumeration variants that are prefixed or suffixed by the same characters.
- string_extend_chars: Checks for the use of
.extend(s.chars())
where s is a&str
orString
. - needless_return: Checks for return statements at the end of a block.
- print_literal: This lint warns about the use of literals as
print!
/println!
args. - implicit_hasher: Checks for public
impl
orfn
missing generalization over different hashers and implicitly defaulting to the default hashing algorithm (SipHash). - needless_pass_by_value: Checks for functions taking arguments by value, but not consuming them in its body.
- trivial_regex: Checks for trivial regex
creation (with
Regex::new
,RegexBuilder::new
orRegexSet::new
). - while_let_on_iterator: Checks for
while let
expressions on iterators. - redundant_pattern: Checks for patterns in the form
name @ _
. - match_overlapping_arm: Checks for overlapping match arms.
- just_underscores_and_digits: Checks if you have variables whose name consists of just underscores and digits.
- ok_expect: Checks for usage of
ok().expect(..)
. - empty_loop: Checks for empty
loop
expressions. - explicit_into_iter_loop: Checks for loops on
y.into_iter()
wherey
will do, and suggests the latter. - if_let_redundant_pattern_matching: Lint for redundant pattern matching over
Result
orOption
complexity (Warn)
- option_option: Checks for use of
Option<Option<_>>
in function signatures and type definitions - precedence: Checks for operations where precedence may be unclear
and suggests to add parentheses. Currently it catches the following:
- mixed usage of arithmetic and bit shifting/combining operators without parentheses
- a "negative" numeric literal (which is really a unary
-
followed by a numeric literal) followed by a method call
- useless_transmute: Checks for transmutes to the original type of the object and transmutes that could be a cast.
- partialeq_ne_impl: Checks for manual re-implementations of
PartialEq::ne
. - redundant_closure_call: Detects closures called in the same expression where they are defined.
- manual_swap: Checks for manual swapping.
- option_map_unit_fn: Checks for usage of
option.map(f)
where f is a function or closure that returns the unit type. - overflow_check_conditional: Detects classic underflow/overflow checks.
- transmute_ptr_to_ref: Checks for transmutes from a pointer to a reference.
- chars_next_cmp: Checks for usage of
.chars().next()
on astr
to check if it starts with a given char. - transmute_bytes_to_str: Checks for transmutes from a
&[u8]
to a&str
. - identity_conversion: Checks for always-identical
Into
/From
conversions. - double_parens: Checks for unnecessary double parentheses.
- zero_divided_by_zero: Checks for
0.0 / 0.0
. - useless_asref: Checks for usage of
.as_ref()
or.as_mut()
where the types before and after the call are the same. - too_many_arguments: Checks for functions with too many parameters.
- range_zip_with_len: Checks for zipping a collection with the range of
0.._.len()
. - temporary_assignment: Checks for construction of a structure or tuple just to assign a value in it.
- no_effect: Checks for statements which have no effect.
- short_circuit_statement: Checks for the use of short circuit boolean conditions as a statement.
- cast_lossless: Checks for on casts between numerical types that may be replaced by safe conversion functions.
- unnecessary_operation: Checks for expression statements that can be reduced to a sub-expression.
- cyclomatic_complexity: Checks for methods with high cyclomatic complexity.
- while_let_loop: Detects
loop + match
combinations that are easier written as awhile let
loop. - needless_update: Checks for needlessly including a base struct on update when all fields are changed anyway.
- identity_op: Checks for identity operations, e.g.
x + 0
. - search_is_some: Checks for an iterator search (such as
find()
,position()
, orrposition()
) followed by a call tois_some()
. - useless_format: Checks for the use of
format!("string literal with no argument")
andformat!("{}", foo)
wherefoo
is a string. - diverging_sub_expression: Checks for diverging calls that are not match arms or statements.
- transmute_ptr_to_ptr: Checks for transmutes from a pointer to a pointer, or from a reference to a reference.
- crosspointer_transmute: Checks for transmutes between a type
T
and*T
. - needless_borrowed_reference: Checks for useless borrowed references.
- transmute_int_to_char: Checks for transmutes from an integer to a
char
. - nonminimal_bool: Checks for boolean expressions that can be written more concisely.
- needless_bool: Checks for expressions of the form
if c { true } else { false }
(or vice versa) and suggest using the condition directly. - misrefactored_assign_op: Checks for
a op= a op b
ora op= b op a
patterns. - neg_cmp_op_on_partial_ord: Checks for the usage of negated comparison operators on types which only implement
PartialOrd
(e.g.f64
). - zero_prefixed_literal: Warns if an integral constant literal starts with
0
. - bool_comparison: Checks for expressions of the form
x == true
(or vice versa) and suggest using the variable directly. - extra_unused_lifetimes: Checks for lifetimes in generics that are never used anywhere else.
- int_plus_one: Checks for usage of
x >= y + 1
orx - 1 >= y
(and<=
) in a block - duration_subsec: Checks for calculation of subsecond microseconds or milliseconds
from other
Duration
methods. - unnecessary_cast: Checks for casts to the same type.
- unused_label: Checks for unused labels.
- result_map_unit_fn: Checks for usage of
result.map(f)
where f is a function or closure that returns the unit type. - clone_on_copy: Checks for usage of
.clone()
on aCopy
type. - unit_arg: Checks for passing a unit value as an argument to a function without using a unit literal (
()
). - transmute_int_to_float: Checks for transmutes from an integer to a float.
- double_comparisons: Checks for double comparisons that could be simplified to a single expression.
- eval_order_dependence: Checks for a read and a write to the same variable where whether the read occurs before or after the write depends on the evaluation order of sub-expressions.
- ref_in_deref: Checks for references in expressions that use auto dereference.
- mut_range_bound: Checks for loops which have a range bound that is a mutable variable
- transmute_int_to_bool: Checks for transmutes from an integer to a
bool
. - needless_lifetimes: Checks for lifetime annotations which can be removed by relying on lifetime elision.
- explicit_counter_loop: Checks
for
loops over slices with an explicit counter and suggests the use of.enumerate()
. - explicit_write: Checks for usage of
write!()
/writeln()!
which can be replaced with(e)print!()
/(e)println!()
- deref_addrof: Checks for usage of
*&
and*&mut
in expressions. - filter_next: Checks for usage of
_.filter(_).next()
. - borrowed_box: Checks for use of
&Box<T>
anywhere in the code. - type_complexity: Checks for types used in structs, parameters and
let
declarations above a certain complexity threshold. - match_as_ref: Checks for match which is used to add a reference to an
Option
value. - char_lit_as_u8: Checks for expressions where a character literal is cast
to
u8
and suggests using a byte literal instead.
perf (Warn)
- mutex_atomic: Checks for usages of
Mutex<X>
where an atomic will do. - large_enum_variant: Checks for large size differences between variants on
enum
s. - manual_memcpy: Checks for for-loops that manually copy items between slices that could be optimized by having a memcpy.
- boxed_local: Checks for usage of
Box<T>
where an unboxedT
would work fine. - box_vec: Checks for use of
Box<Vec<_>>
anywhere in the code. - useless_vec: Checks for usage of
&vec![..]
when using&[..]
would be possible. - map_entry: Checks for uses of
contains_key
+insert
onHashMap
orBTreeMap
. - cmp_owned: Checks for conversions to owned values just for the sake of a comparison.
- or_fun_call: Checks for calls to
.or(foo(..))
,.unwrap_or(foo(..))
, etc., and suggests to useor_else
,unwrap_or_else
, etc., orunwrap_or_default
instead. - unused_collect: Checks for using
collect()
on an iterator without using the result. - expect_fun_call: Checks for calls to
.expect(&format!(...))
,.expect(foo(..))
, etc., and suggests to useunwrap_or_else
instead - naive_bytecount: Checks for naive byte counts
- iter_nth: Checks for use of
.iter().nth()
(and the related.iter_mut().nth()
) on standard library types with O(1) element access. - single_char_pattern: Checks for string methods that receive a single-character
str
as an argument, e.g._.split("x")
.
pedantic (Allow)
- expl_impl_clone_on_copy: Checks for explicit
Clone
implementations forCopy
types. - result_map_unwrap_or_else: Checks for usage of
result.map(_).unwrap_or_else(_)
. - maybe_infinite_iter: Checks for iteration that may be infinite.
- cast_possible_wrap: Checks for casts from an unsigned type to a signed type of
the same size. Performing such a cast is a 'no-op' for the compiler,
i.e. nothing is changed at the bit level, and the binary representation of
the value is reinterpreted. This can cause wrapping if the value is too big
for the target signed type. However, the cast works as defined, so this lint
is
Allow
by default. - cast_sign_loss: Checks for casts from a signed to an unsigned numerical
type. In this case, negative values wrap around to large positive values,
which can be quite surprising in practice. However, as the cast works as
defined, this lint is
Allow
by default. - enum_glob_use: Checks for
use Enum::*
. - match_same_arms: Checks for
match
with identical arm bodies. - single_match_else: Checks for matches with a two arms where an
if let
will usually suffice. - pub_enum_variant_names: Detects enumeration variants that are prefixed or suffixed by the same characters.
- use_self: Checks for unnecessary repetition of structure name when a
replacement with
Self
is applicable. - option_map_unwrap_or_else: Checks for usage of
_.map(_).unwrap_or_else(_)
. - items_after_statements: Checks for items declared after some statement in a block.
- empty_enum: Checks for
enum
s with no variants. - needless_continue: The lint checks for
if
-statements appearing in loops that contain acontinue
statement in either their main blocks or theirelse
-blocks, when omitting theelse
-block possibly with some rearrangement of code can make the code easier to understand. - string_add_assign: Checks for string appends of the form
x = x + y
(withoutlet
!). - used_underscore_binding: Checks for the use of bindings with a single leading underscore.
- cast_possible_truncation: Checks for on casts between numerical types that may
truncate large values. This is expected behavior, so the cast is
Allow
by default. - doc_markdown: Checks for the presence of
_
,::
or camel-case words outside ticks in documentation. - unseparated_literal_suffix: Warns if literal suffixes are not separated by an underscore.
- if_not_else: Checks for usage of
!
or!=
in an if condition with an else branch. - filter_map: Checks for usage of
_.filter(_).map(_)
,_.filter(_).flat_map(_)
,_.filter_map(_).flat_map(_)
and similar. - stutter: Detects type names that are prefixed or suffixed by the containing module's name.
- similar_names: Checks for names that are very similar and thus confusing.
- replace_consts: Checks for usage of
ATOMIC_X_INIT
,ONCE_INIT
, anduX/iX::MIN/MAX
. - option_map_unwrap_or: Checks for usage of
_.map(_).unwrap_or(_)
. - inline_always: Checks for items annotated with
#[inline(always)]
, unless the annotated function is empty or simply panics. - linkedlist: Checks for usage of any
LinkedList
, suggesting to use aVec
or aVecDeque
(formerly calledRingBuf
). - mut_mut: Checks for instances of
mut mut
references. - non_ascii_literal: Checks for non-ASCII characters in string literals.
- unicode_not_nfc: Checks for string literals that contain Unicode in a form that is not equal to its NFC-recomposition.
- cast_precision_loss: Checks for casts from any numerical to a float type where
the receiving type cannot store all values from the original type without
rounding errors. This possible rounding is to be expected, so this lint is
Allow
by default. Basically, this warns on casting any integer with 32 or more bits tof32
or any 64-bit integer tof64
. - invalid_upcast_comparisons: Checks for comparisons where the relation is always either true or false, but where one side has been upcast so that the comparison is necessary. Only integer types are checked.
nursery (Allow)
- empty_line_after_outer_attr: Checks for empty lines after outer attributes
- needless_borrow: Checks for address of operations (
&
) that are going to be dereferenced immediately by the compiler. - mutex_integer: Checks for usages of
Mutex<X>
whereX
is an integral type. - range_plus_one: Checks for exclusive ranges where 1 is added to the
upper bound, e.g.
x..(y+1)
. - fallible_impl_from: Checks for impls of
From<..>
that containpanic!()
orunwrap()
- unnecessary_unwrap: Checks for calls of
unwrap[_err]()
that cannot fail.
restriction (Allow)
- integer_arithmetic: Checks for plain integer arithmetic.
- shadow_reuse: Checks for bindings that shadow other bindings already in scope, while reusing the original value.
- option_unwrap_used: Checks for
.unwrap()
calls onOption
s. - assign_ops: Checks for compound assignment operations (
+=
and similar). - shadow_unrelated: Checks for bindings that shadow other bindings already in scope, either without a initialization or with one that does not even use the original value.
- clone_on_ref_ptr: Checks for usage of
.clone()
on a ref-counted pointer, (Rc
,Arc
,rc::Weak
, orsync::Weak
), and suggests calling Clone via unified function syntax instead (e.g.Rc::clone(foo)
). - wrong_pub_self_convention: This is the same as
wrong_self_convention
, but for public items. - indexing_slicing: Checks for usage of indexing or slicing.
- float_arithmetic: Checks for float arithmetic.
- string_add: Checks for all instances of
x + _
wherex
is of typeString
, but only ifstring_add_assign
does not match. - else_if_without_else: Checks for usage of if expressions with an
else if
branch, but without a finalelse
branch. - shadow_same: Checks for bindings that shadow other bindings already in scope, while just changing reference level or mutability.
- missing_docs_in_private_items: Warns if there is missing doc for any documentable item (public or private).
- use_debug: Checks for use of
Debug
formatting. The purpose of this lint is to catch debugging remnants. - mem_forget: Checks for usage of
std::mem::forget(t)
wheret
isDrop
. - unimplemented: Checks for usage of
unimplemented!
. - print_stdout: Checks for printing on stdout. The purpose of this lint is to catch debugging remnants.
- result_unwrap_used: Checks for
.unwrap()
calls onResult
s. - multiple_inherent_impl: Checks for multiple inherent implementations of a struct
- decimal_literal_representation: Warns if there is a better representation for a numeric literal.
- float_cmp_const: Checks for (in-)equality comparisons on floating-point
value and constant, except in functions called
*eq*
(which probably implement equality for a type involving floats).
Rationale and alternatives
We don't particularly need a 1.0, however it's good to have a milestone here, and a general idea of stability as we move forward in this process.
It's also good to have some community involvement in the lint design/categorization process since Clippy lints both reflect and affect the general style of the community.
Unresolved questions
Through the process of this RFC we hope to determine if there are lints which need to be uplifted, recategorized, or removed.