From 97d31c8ae0b8505e3a25385da16562bbb6fa9c33 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 3 Apr 2023 17:32:09 +0200 Subject: [PATCH] New chapter: Defining Lints Co-authored-by: Nahua --- book/src/SUMMARY.md | 1 + book/src/development/defining_lints.md | 161 +++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 book/src/development/defining_lints.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 22fbdce75e8..f6378b1fb90 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -13,6 +13,7 @@ - [Development](development/README.md) - [Basics](development/basics.md) - [Adding Lints](development/adding_lints.md) + - [Defining Lints](development/defining_lints.md) - [Lint Passes](development/lint_passes.md) - [Type Checking](development/type_checking.md) - [Macro Expansions](development/macro_expansions.md) diff --git a/book/src/development/defining_lints.md b/book/src/development/defining_lints.md new file mode 100644 index 00000000000..17e4c1a1181 --- /dev/null +++ b/book/src/development/defining_lints.md @@ -0,0 +1,161 @@ +# Define New Lints + +The first step in the journey of a new lint is the definition +and registration of the lint in Clippy's codebase. +We can use the Clippy dev tools to handle this step since setting up the +lint involves some boilerplate code. + +In our example, we're going to create a lint to detect functions named `foo` because it is a highly non-descriptive name for a function, so we want to trigger this and fix it early in the development process. + +## Lint name + +A good lint name is important, it is usually given by the issue you're fixing (in the **Lint name** field). If you're unsure if the name you chose fits the lint, you can check the [lint naming guidelines][lint_naming]. Don't worry, if the lint name doesn't fit, a Clippy team member will alert you in the PR process. + +If you're still unsure, you can ask on the [Zulip] or on the Github issue / PR. + +--- + +We'll name our example lint that detects functions named "foo" `foo_functions`. Check the [lint naming guidelines][lint_naming] to see why this name makes sense. + +## Add and Register the Lint + +Now that a name is chosen, we shall register `foo_functions` as a lint to the codebase. +There are two ways to register a lint. + +### Standalone + +If you believe that this new lint is a standalone lint (that doesn't belong to any specific [type](#lint-types) like `functions` or `loops`), you can run the following +command in your Clippy project: + +```sh +$ cargo dev new_lint --name=foo_functions --pass=late --category=pedantic +``` + +There are two things to note here: + +1. We set `--pass=late` in this command to do a late lint pass. The alternative +is an `early` lint pass. We will discuss this difference in a later chapter. + +2. If not provided, the `category` of this new lint will default to `nursery`. +See Clippy's [lint types](../lints.md) for more information on categories. + +The `cargo dev new_lint` command will create a new file: `clippy_lints/src/foo_functions.rs` +as well as [register the lint](#lint-registration). + +Overall, you should notice that the following files are modified or created: + +```sh +$ git status +On branch foo_functions +Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git restore ..." to discard changes in working directory) + modified: CHANGELOG.md + modified: clippy_lints/src/lib.register_lints.rs + modified: clippy_lints/src/lib.register_pedantic.rs + modified: clippy_lints/src/lib.rs + +Untracked files: + (use "git add ..." to include in what will be committed) + clippy_lints/src/foo_functions.rs + tests/ui/foo_functions.rs +``` + +### Specific Type + +If you believe that this new lint belongs to a specific type of lints, +you can run `cargo dev new_lint` with a `--type` option. + +Since our `foo_functions` lint is related to function calls, one could +argue that we should put it into a group of lints that detect some behaviors +of functions, we can put it in the `functions` group. + +Let's run the following command in your Clippy project: + +```sh +$ cargo dev new_lint --name=foo_functions --type=functions --category=pedantic +``` + +This command will create, among other things, a new file: +`clippy_lints/src/{type}/foo_functions.rs`. +In our case, the path will be `clippy_lints/src/functions/foo_functions.rs`. + +Notice how this command has a `--type` flag instead of `--pass`. Unlike a standalone +definition, this lint won't be registered in the traditional sense. Instead, you will +call your lint from within the type's lint pass, found in `clippy_lints/src/{type}/mod.rs`. + +A _type_ is just the name of a directory in `clippy_lints/src`, like `functions` in +the example command. Clippy groups together some lints that share common behaviors, +so if your lint falls into one, it would be best to add it to that type. +Read more about [lint types](#lint-types) below. + +Overall, you should notice that the following files are modified or created: + +```sh +$ git status +On branch foo_functions +Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git restore ..." to discard changes in working directory) + modified: CHANGELOG.md + modified: clippy_lints/src/declared_lints.rs + modified: clippy_lints/src/functions/mod.rs + +Untracked files: + (use "git add ..." to include in what will be committed) + clippy_lints/src/functions/foo_functions.rs + tests/ui/foo_functions.rs +``` + +## Lint registration + +If we run the `cargo dev new_lint` command for a new lint, +the lint will be automatically registered and there is nothing more to do. + +However, sometimes we might want to declare a new lint by hand. +In this case, we'd use `cargo dev update_lints` command afterwards. + +When a lint is manually declared, we might need to register the lint pass +manually in the `register_plugins` function in `clippy_lints/src/lib.rs`: + +```rust +store.register_late_pass(|| Box::new(foo_functions::FooFunctions)); +``` + +As you might have guessed, where there's something late, there is something early: +in Clippy there is a `register_early_pass` method as well. +More on early vs. late passes in a later chapter. + +Without a call to one of `register_early_pass` or `register_late_pass`, +the lint pass in question will not be run. + +## Lint types + +As of the writing of this documentation update, there are 12 categories (a.k.a. _types_) +of lints besides the numerous standalone lints living under `clippy_lints/src/`: + +- `cargo` +- `casts` +- `functions` +- `loops` +- `matches` +- `methods` +- `misc_early` +- `operators` +- `transmute` +- `types` +- `unit_types` +- `utils / internal` (Clippy internal lints) + +These categories group together lints that share some common behaviors. +For instance, as we have mentioned earlier, `functions` groups together lints +that deal with some aspects of function calls in Rust. + +For more information, feel free to compare the lint files under any category +with [All Clippy lints][all_lints] or +ask one of the maintainers. + +[all_lints]: https://rust-lang.github.io/rust-clippy/master/ +[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints +[clippy_team_members]: https://www.rust-lang.org/governance/teams/dev-tools#Clippy%20team +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy \ No newline at end of file