After discussion, here are the configuration files I use for my projects.
Feel free to test, modify and ask me why I've made these choices.
rustfmt configuration file (.rustfmt.toml):
edition="2021"version="Two"required_version="1.5.1"# Enable featuresformat_code_in_doc_comments=truenormalize_doc_attributes=truereorder_impl_items=truewrap_comments=true# Set the width of lineschain_width=90comment_width=132max_width=132use_small_heuristics="Max"# Specific widthstruct_lit_width=18struct_variant_width=35# Import handlinggroup_imports="StdExternalCrate"imports_granularity="Module"# Stylish choicesmatch_block_trailing_comma=trueoverflow_delimited_expr=true
clippy configuration (inside main.rs/lib.rs):
// First: Deny everything.#![deny(clippy::complexity,clippy::correctness,clippy::nursery,clippy::pedantic,clippy::perf,clippy::restriction,clippy::style,clippy::suspicious)]// Then: Allow some parts.#![allow(// Depends on the crate)]
Every clippy lint has documentation available on this website (Rust clippy 1.73).
Furthermore, each lint discussed below is linked to the relevant documentation page.
Before any major changes was made, a number of discussions had to be resolved.
To help the discussion, each of the clippy lints discussed below has been categorised in the following sections:
Consistency: Ensures that a coding style is applied consistently across the project.
Correctness: Detects code that may not behave as expected.
Dead code: Detects extra code that has no impact as not used/necessary.
Documentation: Covers documentation.
Errors: Covers error handling.
Idiom: Identifies code that can be rewritten in a more idiomatic way and usually improves readability.
Log: Covers how to log information.
Naming: Covers how to name identifiers.
Safety: Detects operations that may fail, particularly arithmetic (relevant to be discussed only after the error section).
Unsafe: Covers unsafe blocks
Unfortunately, the clippy categories don't fit well with the notion of categories that I wanted to have for discussion.
How clippy is enabled in the project
The file rr_frontend/.cargo/config.toml is adding rustflags to the Rust workspace.
Beware, this file is only read when cargo is invoked from the workspace itself. This issue has been fixed by adding a new syntax to Cargo.toml in Rust 1.74, which is not available for our toolchain.
This file is currently heavy and follows the "default deny" approach (enable all lints and disable some):
Enable all lints: Enable each clippy category lint (even when not recommanded - see below).
Reasonable lints: Lints that do not require discussion, as they are sane to follow.
Require discussion: Lints that should be discussed because they can change the way the project should behave (in terms of error handling or safety guarantees we want to have).
Avoidable lints: Lints that do not require discussion, as they should NOT be followed in our context.
In the end, the lints in section 3 will be split into sections 2 (agree to follow) and 4 (do not agree to follow), and after the project will be patched, the section 2 will be removed (as all the lints will be satisfied). Also, the lints from section 1 will be set from warnings (-W) to errors (-D).
This file is also divided into sub-categories, corresponding to the clippy categories : This is a memo for later.
It is usually NOT recommended to blindly enable the clippy::restriction category (as done in section 1), as some lints contradict each other to maintain consistency in the project. For example, one lint will disallow any use of <name>/mod.rs to ensure that <name>.rs is used, while another lint will ensure the reverse.
How to "try" a lint against the project
In this branch, cargo clippy invoked in the rr_frontend folder should not give any warning.
Removing any -A<lint> from this file will set the <lint> back to the previous setting, which is "throw error" (made by the section 1).
Then, it suffices to remove any desired line to see all the warnings generated.
Acceptable lints / Avoidable lints
Most of the acceptable lints are categorised in the "dead code" and "idiom" sections.
Most of the avoidable lints are lints that are useful for specific projects that do not correspond to RefinedRust. Most of them are not categorised because it didn't make sense to do so.
Even though I've made a pre-selection, you're welcome to check them out if they seem relevant to you: Feel free to tell me if any lints should be disallowed or allowed.
Lints that requires discussions
To facilitate discussions, each discussion will be posted in a thread below.
Because enums (and modules) already define a name, enum variants (and structures) don't need the same name prefix, as this prefix is already in the qualifying path.
Should RefinedRust panic! or properly pass the error to the main function through Result when something goes wrong?
The former is easier to do, but the former can accurately send errors to the user.
To deal with unreachable branches, one solution might be to use the unreachable! macro, which contains a short explanation of the unreachability.
I think we can enable all the lints except for expect_used and unwrap_used. Both are currently used fairly frequently, and the right way to solve that would be to use a consistent style of error handling across the whole project. That needs some discussion and designing first, and is a separate issue. After that is done some day, we can enable these two lints as well. (enabling them now and fixing uses of unwrap would probably just cover up the issue without a bigger refactor, so I prefer not to enable them now)
In one hand, Debug (and hence {:?}) should not be used for printing.
In the other hand, format!("{x}") should be preferred over format!("{}", x) as the variables are inlined.
I would like to use Debug. Especially for logging, that is very helpful. Most internal structures of rustc don't have Display implementations and their Debug impls are the right thing to use for logging.
The uninlined_format_args seems okay to enable, but I also wouldn't care much, since anyways you can't inline all format args (if projections are used, for instance).
A logger should be used instead of printing to stdout/stderr (with the according debug!, info!, warn! and error! macros).
This may allow one to manipulate the verbosity of the phases (though I do not know if such a logger is given by rustc)
We use such a logger currently, except for output that is intended to be user-facing.
println! is used in a few places for user-facing output. I don't know whether we should make those into warn! or error! calls, given that these calls are not printed to the user by default but have to be enabled with RUST_LOG.
However, we should probably use the rust compiler error reporting APIs for those instead -- but I haven't looked much into what the right APIs are.
My worry if we enable these in one go is that we'll have to add a lot of documentation and then this documentation will be low quality. Maybe we can add more documentation gradually?
Also, some parts of the code are not good enough and change more or less often to deserve such extensive documentation.
So I would prefer waiting a bit more for the code to stabilize more before putting this effort into documentation.
In the meantime, we can add more documentation for new code.
These lints can be interesting if you have ever encountered bad behaviour due to underlying operations hidden by the syntax. It really depends on the project.