EmbarkStudios / rust-ecosystem

Rust wants & tracking for Embark 🦀
http://embark.rs
Apache License 2.0
883 stars 18 forks source link

Be able to disable/enable Clippy lints globally #22

Open repi opened 5 years ago

repi commented 5 years ago

In our monorepo we want to have the same baseline of Clippy lints enabled & disabled across our crates. Right now we need to set this up manually for every crate in lib.rs / bin.rs which is error prone and cumbersome.

This is what almost all of our crates have right now:

#![warn(clippy::all)]
#![warn(rust_2018_idioms)]
#![allow(clippy::new_ret_no_self)] // believe this is fixed in nightly https://github.com/rust-lang-nursery/rust-clippy/issues/3313

We would strongly prefer to instead be able to specify this in our workspace Cargo.toml or root Clippy.toml.

This is tracked in:

repi commented 5 years ago

Ran into this again today with trying to upgrade to Rust 1.34 and where the redundant_closure had been enabled.

All the cases it triggered on was for small member wrapper functions for simple conversions and where it would be a lot more verbose and quite annoying to use the full written out types, examples:

warning: redundant closure found
   --> br/src/network/ml_service.rs:147:45
    |
147 |     TcpListener::bind(&socket_addr).map_err(|e| e.into())
    |                                             ^^^^^^^^^^^^ help: remove closure as shown: `std::convert::Into::into`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure

///////////////////////////////////////////

warning: redundant closure found
   --> texture-synth/src/applet.rs:505:18
    |
505 |             .map(|s| s.to_string())
    |                  ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `std::string::ToString::to_string`
    |
note: lint level defined here
   --> texture-synth/src/lib.rs:1:9
    |
1   | #![warn(clippy::all)]
    |         ^^^^^^^^^^^
    = note: #[warn(clippy::redundant_closure)] implied by #[warn(clippy::all)]
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure

////////////////////////////////////////

warning: redundant closure found
   --> texture-synthesis/src/service.rs:110:62
    |
110 |                     example_guides: source_guides.iter().map(|a| a.to_rgba()).collect(),
    |                                                              ^^^^^^^^^^^^^^^ help: remove closure as shown: `image::dynimage::DynamicImage::to_rgba`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure

We also had a few of these cases where the suggested code didn't work because the types it suggested didn't have the crate:: prefix. Looks like it is tracked in this issue: https://github.com/rust-lang/rust-clippy/issues/3071.

Regardless, this is a case where we would like to disable the redundant_closure lint by default across our crates. But for now likely will have to just add it to existing crates that run into this issue, and maybe manually propagate that lint toggle to the rest of our crates to avoid our devs running into this clippy warning and changing the code in a non-ideal way.

repi commented 5 years ago

We now have 81 crates in our monorepo, all having to specify #![warn(clippy::all)] & co in every lib.rs to get the behavior we want here. It works but it is a bit messy :(

yorickpeterse commented 4 years ago

@repi I ran into this myself for a project I am working on. When running Clippy you can disable lints via the CLI. I ended up putting this in an already existing Makefile, for example:

clippy:
    touch src/lib.rs
    ${CARGO_CMD} clippy -- -Dwarnings \
        -Arenamed_and_removed_lints \
        -Aclippy::new_without_default \
        -Aclippy::needless_range_loop

Here the touch src/lib.rs is needed because otherwise Clippy does not (or at least did not in the past) build the changed files. Here the flag -A is used to globally disable certain lints.

Clippy also supports using a configuration file, but last I checked you can't disable lints using it.

repi commented 4 years ago

@YorickPeterse thanks, that does look like a workable solution for CI.

Though for working locally for users and with tools like RLS I really want a solution where everyone can just run cargo clippy and it has our set of additionally enabled or disabled lints so everyone runs the same lints. Hopefully the clippy config can be extended for that. Or even better: in Cargo.toml

yorickpeterse commented 4 years ago

@repi There is a discussion about adding support for enabling/disabling lints in Cargo.toml in https://github.com/rust-lang/cargo/issues/5034, but it seems that at least since 2018 (example: https://github.com/rust-lang/cargo/pull/5728) not a lot of progress has been made. I wouldn't be surprised if it will take a while for configuration file support to land in Clippy.

repi commented 4 years ago

Yeah doesn't look like very active development of it unfortunately, but hope Cargo/Clippy gets it eventually.

Just added these lines on top of 30 lib.rs files in our workspace to enable more lints for our codebase.

#![warn(clippy::all)]
#![warn(clippy::doc_markdown)]
#![warn(clippy::dbg_macro)]
#![warn(clippy::todo)]
#![warn(clippy::empty_enum)]
#![warn(clippy::enum_glob_use)]
#![warn(clippy::pub_enum_variant_names)]
#![warn(clippy::mem_forget)]
#![warn(clippy::use_self)]
#![warn(clippy::filter_map_next)]
#![warn(clippy::needless_continue)]
#![warn(clippy::needless_borrow)]
#![warn(rust_2018_idioms)]

Copy'n'paste is not pretty, but works.

repi commented 4 years ago

This is getting a bit more silly without this support, we have like 30 crates in our repo where all of their lib.rs start something like this:

#![forbid(unsafe_code)]
#![warn(
    clippy::all,
    clippy::doc_markdown,
    clippy::dbg_macro,
    clippy::todo,
    clippy::empty_enum,
    clippy::enum_glob_use,
    clippy::pub_enum_variant_names,
    clippy::mem_forget,
    clippy::use_self,
    clippy::filter_map_next,
    clippy::needless_continue,
    clippy::needless_borrow,
    clippy::match_wildcard_for_single_variants,
    clippy::if_let_mutex,
    clippy::mismatched_target_os,
    clippy::await_holding_lock,
    clippy::match_on_vec_items,
    clippy::imprecise_flops,
    clippy::suboptimal_flops,
    clippy::lossy_float_literal,
    clippy::rest_pat_in_fully_bound_structs,
    clippy::fn_params_excessive_bools,
    clippy::exit,
    clippy::inefficient_to_string,
    clippy::linkedlist,
    clippy::macro_use_imports,
    clippy::option_option,
    clippy::verbose_file_reads,
    clippy::unnested_or_patterns,
    rust_2018_idioms,
    future_incompatible,
    nonstandard_style
)]

Does work though!

repi commented 3 years ago

We now have ~170 crates across ~20 repositories so have an even larger list of Clippy lints we enable by default across them now scattered and duplicated across 170 locations, which makes it hard to add and esp easy to miss when creating new crates.

We really do need the proper Cargo/Clippy solution for a clippy.toml where we can specify the above list of warn/deny/forbid lints that can be applied for the entire repository: https://github.com/rust-lang/cargo/issues/5034. We'll try and investigate if we can help push the development of that and clippy further. It is a fantastic tool that we want to use more of!

repi commented 3 years ago

We had a good sync with the Clippy team a couple of weeks ago and this is one of the top issues in the Clippy 2021 Roadmap!

cztomsik commented 3 years ago

omg yes!

repi commented 3 years ago

We finally have a workaround for this that works quite well that we are transitioning our projects for, and that is to use .cargo/config.toml and set lint allow/deny CLI parameters with rustflags:

[target.'cfg(all())']
rustflags = [
    # BEGIN - Embark standard lints v0.4
    # do not change or add/remove here, but one can add exceptions after this section
    # for more info see: <https://github.com/EmbarkStudios/rust-ecosystem/issues/59>
    "-Dunsafe_code",
    "-Wclippy::all",
    "-Wclippy::await_holding_lock",
    "-Wclippy::char_lit_as_u8",
]

from #68.

There are some tradeoffs with this approach but overall it works well and dramatically easier to maintain and work with, our main private repo with 80+ crates no longer have to specify our long list of standard lints in every lib.rs/main.rs.

Still would prefer proper Cargo support of a lints.toml or [lints] section to be able to have different lints in different workspaces (in the same repo) and to have a cleaner syntax for this. Though that has been slow moving but tracked in:

So will leave this issue open for now, but tagged as have-workaround

jplatte commented 3 years ago

There seems to be a downside to this in that it only works as of Rust 1.55 (earlier versions raise an error when using -Wclippy::lint with a non-clippy command). Crates should still work with older compilers when used as dependencies, but for MSRV CI jobs it's a problem.

repi commented 3 years ago

Ah interesting, we are on Rust 1.55 and now with our v5 lint set (#67) it also requires 1.55 as we use new lints from it.

Thought initially this approach wouldn't work as also believed that Cargo/Rust would have failed on those unknown clippy lints that only clippy knows about, but was glad to see that it didn't well at least not with 1.55. But good to know that it seems to require 1.55 so must have been a change in how they handle the allow/deny flags (hopefully an intentional one).

jplatte commented 3 years ago

Maybe it's fallout from rustdoc lints being moved to their own namespace a few versions earlier, and people wanting to keep activating them (with new names) in some way where they would be passed to non-rustdoc invocations. It's definitely a reasonable change to just ignore unknown tool-specific lints so I'm sure it will be kept even if it wasn't intentional 😄

jplatte commented 2 years ago

We just hit a very weird issue with the .cargo/config.toml-based workaround, where cargo <command> and cargo <command> --target foo would partially invalidate each other's caches. Turned out a historical design decision in Cargo was the culprit: https://github.com/rust-lang/cargo/issues/4423

Luckily, there is a workaround, you just add this to the config.toml to fix the problem on Nightly (I don't know of any solutions for stable): (see latest comments)

# outside any section
target-applies-to-host = false

[unstable]
target-applies-to-host = true

PR that fixes this for our project, with extra comments: https://github.com/matrix-org/matrix-rust-sdk/pull/737/files

jplatte commented 2 years ago

Regarding my previous comment, do not use that nightly feature if you also want to pass RUSTDOCFLAGS to rustdoc through cargo +nightly doc, the flags will silently get ignored: https://github.com/rust-lang/cargo/issues/10744

jplatte commented 2 years ago

One more update: I've found a good-ish workaround: Just reset target-applies-to-host to its default value when building docs, for example by setting the environment variable CARGO_TARGET_APPLIES_TO_HOST to true. (cc https://github.com/matrix-org/matrix-rust-sdk/pull/757)

9SMTM6 commented 2 years ago

Btw, I've found a different (kinda horrible) workaround:

You can add another binary that declares all the other entrypoints to be linted as modules, and then add the lints in that binary.

It seems to have a number of drawbacks that you'll probably find out quickly (ie it triggers dead_code), but I just thought I'd leave that here, perhaps it turns out to be the least evil for some and/or the main problems can be fixed.

repi commented 2 years ago

Ah thanks for sharing! Kinda horrible indeed but good to know about!

jplatte commented 2 years ago

Ugh, I found that target-applies-to-host entirely disables rustflags-based clippy configuration (it's not just rustdoc) on nightly for regular builds without an explicit --target. This feature breaks more things than it fixes 🙄

ericseppanen commented 2 years ago

I wrote cargo-cranky, which allows easy clippy lint configuration. Lint config goes in a Cranky.toml file and then cargo cranky just runs cargo clippy with the right command line that enables those lints. It's pretty basic so far, but I find it a nice improvement, as it can handle every bin/lib/example in a workspace.

avantgardnerio commented 1 year ago

I need this for the single_range_in_vec_init rule, which is telling me valid code is invalid and offering fixes that would alter behavior:

warning: a `Vec` of `Range` that is only one element
   --> datafusion/physical-expr/src/window/rank.rs:291:32
    |
291 |         test_f64_result(&r, 7, vec![0..7], expected)?;
    |                                ^^^^^^^^^^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_range_in_vec_init
help: if you wanted a `Vec` that contains the entire range, try
    |
291 |         test_f64_result(&r, 7, (0..7).collect::<std::vec::Vec<usize>>(), expected)?;
    |                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
help: if you wanted a `Vec` of len 7, try
    |
291 |         test_f64_result(&r, 7, vec![0; 7], expected)?;
    |                                     ~~~~