Introduction
Hello! Rust has very useful tool, named Cargo. It helps you compile code, run program, run tests and benches, format code using cargo fmt
and lint it using clippy
. In this post we'll talk abou Clippy.
What is Clippy
Clippy is a linter for Rust code. Linter is a static analysis tool, used to prevent errors, bugs, styling mistakes, etc. Clippy includes many lints, or rules, you can enable them and Clippy will show warning or error when you violate this lint.
How to install Clippy
Assume that you already installed Rust, just run following command:
rustup component add clippy
This will download and install Clippy for your current toolchain. Then, you can run Clippy using this commands:
# Check for issues
cargo clippy
# Fix some issues
cargo clippy --fix
How to enable or disable lints
Command line
In CLI interface of Clippy you can enable or disable specific lint by adding to command -A/W/D clippy::lint_name
, where:
- A - allow violation of lint
- W - print warning when you violate lint
- D - deny code if you vioalte lint and show error Example usage:
cargo clippy -- -Aclippy::style -Wclippy::double_neg -Dclippy::perf
This will:
- allow violation of
clippy::style
- print warning when violating
clippy::double_neg
- and deny code that violate
clippy::perf
For CI all warnings can be elevated to errors which will in turn fail the build and cause Clippy to exit with a code other than 0.
cargo clippy -- -Dwarnings
This will deny code that generate any Clippy warnings.
Cargo.toml
You can define levels for lints in your Cargo.toml
like this:
[lints.clippy]
enum_glob_use = "deny"
This will deny any code that violates clippy::enum_glob_use
In code
You can add attributes to your code to allow/warn/deny Clippy lints:
- the whole set of warn-by-default lints using the clippy lint group (
#![allow(clippy::all)]
) - all lints using both the
clippy
andclippy::pedantic
lint groups (#![warn(clippy::all, clippy::pedantic)
]. Note thatclippy::pedantic
contains some very aggressive lints prone to false positives. - only some lints (
#![deny(clippy::single_match, clippy::box_vec)]
, etc.) -
allow
/warn
/deny
can be limited to a single function or module using#[allow(...)]
, etc. # Useful lints groups Clippy includes some groups of lints, that are allowed by default. ##clippy::pedantic
The first group is thepedantic
group. This group contains really opinionated lints, that may have some intentional false positives in order to prevent false negatives. So while this group is ready to be used in production, you can expect to sprinkle multiple#[allow(..)]
s in your code. If you find any false positives, you're still welcome to report them to us for future improvements. ##clippy::restriction
The second group is the restriction group. This group contains lints that "restrict" the language in some way. For example theclippy::unwrap
lint from this group won't allow you to use.unwrap()
in your code. You may want to look through the lints in this group and enable the ones that fit your need.
Note: You shouldn't enable the whole lint group, but cherry-pick lints from this group. Some lints in this group will even contradict other Clippy lints!
Useful lints
Here's list of some useful lints, that I usually use in my projects
clippy::dbg_macro
While dbg!()
macro is very useful for testing purposes, you shouldn't include it into production builds of software.
clippy::else_if_without_else
Checks for usage of if
expressions with an else if
branch, but without a final else
branch. Some coding guidelines require final else branch (e.g., MISRA-C:2004 Rule 14.10).
clippy::exit
Detects calls to the std::process::exit()
function which terminates the program. exit()
immediately terminates the program with no information other than an exit code. This provides no means to troubleshoot a problem, and may be an unexpected side effect.
Codebases may use this lint to require that all exits are performed either by panicking (which produces a message, a code location, and optionally a backtrace) or by returning from main()
(which is a single place to look).
clippy::explicit_into_iter_loop
Checks for loops on y.into_iter()
where y
will do (e.g. it is Vec
or slice), and suggests the latter.
clippy::explicit_iter_loop
Like lint above.
clippy::if_not_else
Checks for usage of ! or != in an if condition with an else branch. Negations reduce the readability of statements.
Example:
if !v.is_empty() {
a()
} else {
b()
}
sould be rewritten as:
if v.is_empty() {
b()
} else {
a()
}
clippy::implicit_return
Checks for missing return statements at the end of a block.
Omitting the return keyword whenever possible is idiomatic Rust code, but:
- Programmers coming from other languages might prefer the expressiveness of return.
- It’s possible to miss the last returning statement because the only difference is a missing ;.
- Especially in bigger code with multiple return paths, having a return keyword makes it easier to find the corresponding statements.
##
clippy::infinite_loop
Checks for infinite loops in a function where the return type is not!
and lint accordingly. 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. ##clippy::manual_let_else
Warn of cases wherelet...else
could be used.let...else
provides a standard construct for this pattern that people can easily recognize. It’s also more compact. ##clippy::match_bool
Checks for matches wherematch
expression is abool
. It suggests to replace the expression with anif...else
block. ##clippy::mem_forget
Checks for usage ofstd::mem::forget(t)
wheret
isDrop
or has a field that implementsDrop
.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 to prohibit the simple ones. ##clippy::missing_panics_doc
Checks the doc comments of publicly visible functions that may panic and warns if there is no# Panics
section. ##clippy::panic
This macro, or panics in general, may be unwanted in production code. ##clippy::pub_use
Restricts the usage ofpub use ...
. A project may wish to limitpub use
instances to prevent unintentional exports, or to encourage placing exported items directly in public modules. ##clippy::similar_names
Checks for names that are very similar and thus confusing.
Note: this lint looks for similar names throughout each scope. To allow it, you need to allow it on the scope level, not on the name that is reported.
clippy::todo
Checks for usage of todo!
. The todo!
macro indicates the presence of unfinished code, so it should not be present in production code.
clippy::too_many_lines
Checks for functions with a large amount of lines. Functions with a lot of lines are harder to understand due to having to look at a larger amount of code to understand what the function is doing. Consider splitting the body of the function into multiple functions.
By default it is 100
lines
clippy::wildcard_imports
Checks for wildcard imports use _::*
. wildcard imports can pollute the namespace. This is especially bad if you try to import something through a wildcard, that already has been imported by name from a different source.
Conclusion
In this post I wrote some useful Clippy lints, that I usually use.
Write feedback on comments, see my projects on GitHub, subscribe to my Telegram chhannel about Rust. Thanks for reading this!
Top comments (0)