Giter Club home page Giter Club logo

rust-clippy's Introduction

Clippy

Clippy Test License: MIT OR Apache-2.0

A collection of lints to catch common mistakes and improve your Rust code.

There are over 700 lints included in this crate!

Lints are divided into categories, each with a default lint level. You can choose how much Clippy is supposed to annoy help you by changing the lint level by category.

Category Description Default level
clippy::all all lints that are on by default (correctness, suspicious, style, complexity, perf) warn/deny
clippy::correctness code that is outright wrong or useless deny
clippy::suspicious code that is most likely wrong or useless warn
clippy::style code that should be written in a more idiomatic way warn
clippy::complexity code that does something simple but in a complex way warn
clippy::perf code that can be written to run faster warn
clippy::pedantic lints which are rather strict or have occasional false positives allow
clippy::restriction lints which prevent the use of language and library features1 allow
clippy::nursery new lints that are still under development allow
clippy::cargo lints for the cargo manifest allow

More to come, please file an issue if you have ideas!

The restriction category should, emphatically, not be enabled as a whole. The contained lints may lint against perfectly reasonable code, may not have an alternative suggestion, and may contradict any other lints (including other categories). Lints should be considered on a case-by-case basis before enabling.


Table of contents:

Usage

Below are instructions on how to use Clippy as a cargo subcommand, in projects that do not use cargo, or in Travis CI.

As a cargo subcommand (cargo clippy)

One way to use Clippy is by installing Clippy through rustup as a cargo subcommand.

Step 1: Install Rustup

You can install Rustup on supported platforms. This will help us install Clippy and its dependencies.

If you already have Rustup installed, update to ensure you have the latest Rustup and compiler:

rustup update

Step 2: Install Clippy

Once you have rustup and the latest stable release (at least Rust 1.29) installed, run the following command:

rustup component add clippy

If it says that it can't find the clippy component, please run rustup self update.

Step 3: Run Clippy

Now you can run Clippy by invoking the following command:

cargo clippy

Automatically applying Clippy suggestions

Clippy can automatically apply some lint suggestions, just like the compiler. Note that --fix implies --all-targets, so it can fix as much code as it can.

cargo clippy --fix

Workspaces

All the usual workspace options should work with Clippy. For example the following command will run Clippy on the example crate:

cargo clippy -p example

As with cargo check, this includes dependencies that are members of the workspace, like path dependencies. If you want to run Clippy only on the given crate, use the --no-deps option like this:

cargo clippy -p example -- --no-deps

Using clippy-driver

Clippy can also be used in projects that do not use cargo. To do so, run clippy-driver with the same arguments you use for rustc. For example:

clippy-driver --edition 2018 -Cpanic=abort foo.rs

Note that clippy-driver is designed for running Clippy only and should not be used as a general replacement for rustc. clippy-driver may produce artifacts that are not optimized as expected, for example.

Travis CI

You can add Clippy to Travis CI in the same way you use it locally:

language: rust
rust:
  - stable
  - beta
before_script:
  - rustup component add clippy
script:
  - cargo clippy
  # if you want the build job to fail when encountering warnings, use
  - cargo clippy -- -D warnings
  # in order to also check tests and non-default crate features, use
  - cargo clippy --all-targets --all-features -- -D warnings
  - cargo test
  # etc.

Note that adding -D warnings will cause your build to fail if any warnings are found in your code. That includes warnings found by rustc (e.g. dead_code, etc.). If you want to avoid this and only cause an error for Clippy warnings, use #![deny(clippy::all)] in your code or -D clippy::all on the command line. (You can swap clippy::all with the specific lint category you are targeting.)

Configuration

Allowing/denying lints

You can add options to your code to allow/warn/deny Clippy lints:

  • the whole set of Warn lints using the clippy lint group (#![deny(clippy::all)]). Note that rustc has additional lint groups.

  • all lints using both the clippy and clippy::pedantic lint groups (#![deny(clippy::all)], #![deny(clippy::pedantic)]). Note that clippy::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.

Note: allow means to suppress the lint for your code. With warn the lint will only emit a warning, while with deny the lint will emit an error, when triggering for your code. An error causes clippy to exit with an error code, so is useful in scripts like CI/CD.

If you do not want to include your lint levels in your code, you can globally enable/disable lints by passing extra flags to Clippy during the run:

To allow lint_name, run

cargo clippy -- -A clippy::lint_name

And to warn on lint_name, run

cargo clippy -- -W clippy::lint_name

This also works with lint groups. For example, you can run Clippy with warnings for all lints enabled:

cargo clippy -- -W clippy::pedantic

If you care only about a single lint, you can allow all others and then explicitly warn on the lint(s) you are interested in:

cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...

Configure the behavior of some lints

Some lints can be configured in a TOML file named clippy.toml or .clippy.toml. It contains a basic variable = value mapping e.g.

avoid-breaking-exported-api = false
disallowed-names = ["toto", "tata", "titi"]

The table of configurations contains all config values, their default, and a list of lints they affect. Each configurable lint , also contains information about these values.

For configurations that are a list type with default values such as disallowed-names, you can use the unique value ".." to extend the default values instead of replacing them.

# default of disallowed-names is ["foo", "baz", "quux"]
disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]

Note

clippy.toml or .clippy.toml cannot be used to allow/deny lints.

To deactivate the “for further information visit lint-link” message you can define the CLIPPY_DISABLE_DOCS_LINKS environment variable.

Specifying the minimum supported Rust version

Projects that intend to support old versions of Rust can disable lints pertaining to newer features by specifying the minimum supported Rust version (MSRV) in the clippy configuration file.

msrv = "1.30.0"

Alternatively, the rust-version field in the Cargo.toml can be used.

# Cargo.toml
rust-version = "1.30"

The MSRV can also be specified as an attribute, like below.

#![feature(custom_inner_attributes)]
#![clippy::msrv = "1.30.0"]

fn main() {
  ...
}

You can also omit the patch version when specifying the MSRV, so msrv = 1.30 is equivalent to msrv = 1.30.0.

Note: custom_inner_attributes is an unstable feature, so it has to be enabled explicitly.

Lints that recognize this configuration option can be found here

Contributing

If you want to contribute to Clippy, you can find more information in CONTRIBUTING.md.

License

Copyright 2014-2024 The Rust Project Developers

Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. Files in the project may not be copied, modified, or distributed except according to those terms.

Footnotes

  1. Some use cases for restriction lints include:

rust-clippy's People

Contributors

alexendoo avatar birkenfeld avatar blyxyas avatar bors avatar camsteffen avatar centri3 avatar cjgillot avatar compiler-errors avatar ebroto avatar flip1995 avatar giraffate avatar guillaumegomez avatar jarcho avatar johntitor avatar llogiq avatar manishearth avatar matthiaskrgr avatar mcarton avatar nnethercote avatar oli-obk avatar phansch avatar rail-rain avatar sinkuu avatar smoelius avatar tako8ki avatar tesuji avatar thibsg avatar xfrednet avatar y-nak avatar y21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rust-clippy's Issues

Returning Box<T>

We explicitly say in the pointer guide that you usually shouldn't do this, return T instead and box it.

lint to warn on identity operations (e.g. x + 0)

Patterns to match:

x + 0, x - 0, x | 0, x << 0, x >> 0, x ^ 0, x * 1, x / 1, x & -1

(and vice versa, e.g. 0 + x)

Note that x & x and x | x are already handled by eq_op, so we won't include them here

foo.unwrap_or(panic!(…))

This should either be .expect() or .unwrap_or_else(|| panic!()) (if they want the formatting panic provides). Ideally this would be generalised to any diverging function (fn(…) -> !) as well.

`unwrap()` of Option<_> or Result<_>

I believe we should warn about usage of unwrap() of optional types. unwrap() is essentially a pattern match with _ => panic!(), but there are often ways to continue execution of program w/o failing.

Today, it's common to find code like

extern crate term;

fn main() {
    let mut t = term::stdout().unwrap();

    t.fg(term::color::GREEN).unwrap();
    (write!(t, "hello, ")).unwrap();

    t.fg(term::color::RED).unwrap();
    (writeln!(t, "world!")).unwrap();

    t.reset().unwrap();
}

As one might learn pretty quickly, unwrap()ing a None returned by term::stdout() will lead to failure of task. This is, of course, specified in docs. But it's certainly not obvious that this is not a "safe" operation — it may lead to "crash". Not "hard" crash, because it will be handled by Rust runtime. It produces error about unwrapping None. But it's a crash nevertheless.

Warnings from compiler that .unwrap() is essentially a pattern match w/o "catch-all" case are missing here. We do get warnings when not all variants of enum are handled, so why skip it here?

unwrap() of Option<_> is a hack. It's convenient, I know — but it's the sort of convenience we disdain JavaScript and PHP for. I also understand that one is extremely likely to use unwrap() in closures because "heck, I only need to filter/map/reduce stuff, I don't want my closure to spend 5 lines!". Programmer uses it there and then forgets about it. Voila — safety is needlessly violated.

I think a programmer should be forced to actively discard any failure condition. It makes for explicit decision making about not handling an error.

In Rust, in it's present state, unwrap() is the easiest and simplest way to Get Things Done. This shortcut will be taken by many and many people who will then later complain about Rust not being secure despite claiming itself "preventing almost all crashes".

I see you're using a DList!

Did you mean do use practically any other data structure?

Every repository I've seen that uses this for anything useful reimplements the internals to gain access to the raw links / raw nodes anyway, I doubt this will catch many/any false positives.

trait with a len() method but without is_empty() method

Regarding my failed attempt to fully solve #32 (which would require more typeck than external lints can currently acquire), I thought about the social contract around .len() and .is_empty(). While we don't have a Bounded trait that defines .len() and implements .is_empty(), we can still ask implementers to provide the latter.

There is some precedence to the use of is_empty: E.g. in Java, the Collection interface defines boolean isEmpty() with the usual meaning. C++'s STL defines empty() on all containers, Ocaml at least defines is_empty for stacks. Python's lists and Lua's tables are basically arrays, so they have no problem with using len(_).

In any event, we could add a lint that looks for traits which define .len() but do not define .is_empty() and ask the implementer to consider adding it. This would also remove the need for method lookup on that other lint – if most traits have .is_empty(), we won't need to care for the few remaining false positives, right?

A basic implementation would check_item for ItemTraits and see if the contained TraitItems fail to adhere to the social contract.

Make elision better

I wonder if we can catch cases like these where elision breaks things.

Basically, when the returned value has no relation to the inputs, lint that elision might not be wanted.

Exact heuristics would be tough to figure out, but I think it's doable (I've got a rough idea)

Ideally this should go into the compiler, but we can start it as a lint.

if x { true } else { false }

Not a Rust-specific problem but I've seen it a lot in code from people who are new to programming in general.

Could generalize to find other forms that are better expressed by logical operators.

mut_mut triggers for regex! macro

I just came across this warning:

src/helpers/adjust_header_level.rs:9:28: 9:71 warning: This expression mutably borrows a mutable reference. Consider reborrowing, #[warn(mut_mut)] on by default
src/helpers/adjust_header_level.rs:9     let headline_pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$");
                                                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.rs:1:1: 24:1 note: in expansion of regex!

This does not seem very useful. (I totally understand why this can be problematic to fix in clippy, though.)

Box<Vec<T>> warning triggered spuriously

The Box<Vec<T>> warning appears to be being triggered when I box a closure (necessary in this case to make the struct Sized).

src/native_types.rs:93:13: 93:65 note: Vec<T> is already on the heap, Box<Vec<T>> makes an extra allocation
src/native_types.rs:93   pub run : Box<Fn(Vec<HValue>) -> Vec<HValue> + 'static + Send>
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

add another lint to bit_mask to warn on ineffective masks

Currently, bad_bit_mask ignores masks that do not make the result of the whole expression constant, but don't add any value, e.g. x|0 or x & -1 or even x | 1 > 2 (because the former are always equal to x and latter is equal to x > 2 – they're not wrong per se, but may be misleading.

So let's have BitMask implement a second lint type (that is Warn instead of Deny), which I'd call ineffective_bit_mask.

Approximate known const found

Someone writing 3.1415 should probably use some definition of PI. We should look up other constants in the standard library.

warn on #[inline(always)]

Following a discussion on reddit, this is almost always a bad idea, so much that requiring to explicitly allow the few false positives (where you really mean it) is acceptable.

Ignoring results, especially 'must_use'

I've seen people do this regularly, I guess it's flagged from the must_use lint and people use this to silence the warnings.

let _ = stream.write(..);

Recommendation:

// ideally pass the error up
try!(stream.write(..))
// or else, panic
stream.write(..).unwrap()
// or add the allow(unused_must_use) attribute

comparison to NAN

Check for (doomed) comparisons to std::f32::NAN or std::f64::NAN.

(== or !=) exact comparison to f32/f64

As we all know, floating point operations carry the risk of rounding errors, thus comparing a float with == is asking for trouble. Suggest abs(x - y) < epsilon (for some value of epsilon) instead.

&mut &mut T

Raise your hand if you've ever needed to do this. The only tricky part is recommending an alternative since if you are even trying to do this something is probably badly wrong.

Rc<T> where clone() is never called.

I don't know whether this is actually feasible to do a lint for, but just use a Box here (if the box is too small Rust will recommend a plain T).

Name Shadowing

Some people (myself included) think that name shadowing makes code harder to reason about.

Now of course there is a continuum of shadowing operations:

  • shadow_same: The name is re-bound to the same data (e.g. let mut x = &mut x; for mutable re-bind)
  • shadow_reuse_change: The name is re-used in the bound expression (e.g. let x = x + 1;)
  • shadow_foreign: The name is re-bound without even using the original value

We could create lints for all three groups, plus a shadow_reuse lint group that combines shadow_same and shadow_reuse_change and a shadow lint group that combines all three.

Now for those lints, we want to make the macro check more strict in that we do not check within macro expansions at all.

I think (but am open to discussion) that the shadow_foreign lint should be Warn by default, while the others should be Allow. This won't disturb people too much but still makes for fairly readable code. Organizations or projects can then opt to Deny all shadowing, or whatever suits them.

Unintuitive operator precedence

Warn on instances of _ << _ + _ (or similar cases involving seldom-used operators). While those are not wrong, they can become footguns for anyone trying to reason about the code.

Suggest parenthesizing the operation.

Box<T> where T is small

Where:

  • Small means "three words or fewer" (a la Vec)
  • Box is not required for monomorphization
  • T is not actually a generic (that is, your code doesn't have to work with potentially differently sized Ts).

Note that HashMap is five words by default, so it actually shouldn't qualify for this lint (IMO) but it would subsume the Vec lint.

x.iter().zip(range(0,x.len()))

I have seen this a couple of times, don't know how easy it is to detect (given the variations) but the person wants is x.iter().enumerate().

for index in range() used for iteration over slice

This might have to wait a while, and it might be really hard / impossible to detect, but for a simple loop like this:

let x = something_with_Slice<uint>_implemented;
for i in range(0, n) {
  /*every instance of x is called as x[i], where i is the same immutable uint (*not* MutSlice etc.) */
}

you should just use an iterator.

Add warning when declaring binding with type `()`

I just read https://internals.rust-lang.org/t/two-little-proposals/2148 and @Xirdus' first proposal sounds like a good addition to clippy:

Make it a warning (or even an error) to declare a variable of type (), except when it's due to generic type resolution. This is pretty useless, but some people new to Rust might do it by mistake, for example by saving the result of assignment. Also would make finding errors like unwanted semicolon easier in some cases.

Can't compile with recent nightly

Maybe you already know this, but it couldn't find an issue. (I'm compiling this project but it shouldn't matter.)

$ cargo run --features "dev" --release
   Compiling clippy v0.0.4 (https://github.com/Manishearth/rust-clippy.git#62f0fe0c)
/Users/pascal/.multirust/toolchains/nightly/cargo/git/checkouts/rust-clippy-2d80226e8d82d2cc/master/src/ptr_arg.rs:30:11: 30:39 error: this pattern has 5 fields, but the corresponding variant has 6 fields [E0023]
/Users/pascal/.multirust/toolchains/nightly/cargo/git/checkouts/rust-clippy-2d80226e8d82d2cc/master/src/ptr_arg.rs:30       if let &ItemFn(ref decl, _, _, _, _) = &item.node {
                                                                                                                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: in expansion of if let expansion
/Users/pascal/.multirust/toolchains/nightly/cargo/git/checkouts/rust-clippy-2d80226e8d82d2cc/master/src/ptr_arg.rs:30:3: 32:4 note: expansion site
/Users/pascal/.multirust/toolchains/nightly/cargo/git/checkouts/rust-clippy-2d80226e8d82d2cc/master/src/ptr_arg.rs:30:11: 30:39 help: run `rustc --explain E0023` to see a detailed explanation
error: aborting due to previous error
Could not compile `clippy`.

To learn more, run the command again with --verbose.
$ rustc --version --verbose
rustc 1.2.0-nightly (7c4eedc21 2015-05-25) (built 2015-05-24)
binary: rustc
commit-hash: 7c4eedc21e609446671cc838d08473421917c353
commit-date: 2015-05-25
build-date: 2015-05-24
host: x86_64-apple-darwin
release: 1.2.0-nightly

Detecting collapsable if is too eager

This snippet is warned with warning: This if statement can be collapsed. Try: if a == 0 && b == 0, #[warn(collapsible_if)] on by default. Putting a semicolon after the second if block removes the warning, but doesn't seem like it should be necessary.

    let a = 0;
    let b = 0;
    if a == 0 {
        print!("a is zero");
        if b == 0 {
            println!("a and b is zero");
        }
    }

does not compile on rust stable?

When i want to use this i get the following error:

clippy-0.0.4/src/bit_mask.rs:153:32: 153:80 error: this function takes 2 parameters but 3 parameters were supplied [E0061]
clippy-0.0.4/src/bit_mask.rs:153             .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None))


infinite loops

There are a few patterns we can search for (while true { ... } without break or return, method calling itself outside of if or closure, or within if true.

This is one of the cases where constant folding would enable us to implement more powerful checks.

incorrect use of min/max

(Analogous to the bad_bit_mask lint, we can detect min(x, max(y, _)) where x < y (this will always return x) or vice versa.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.