New chapter: Defining Lints
Co-authored-by: Nahua <kangnahua@gmail.com>
This commit is contained in:
parent
710db18ccd
commit
97d31c8ae0
@ -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)
|
||||
|
161
book/src/development/defining_lints.md
Normal file
161
book/src/development/defining_lints.md
Normal file
@ -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.
|
||||
<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
|
||||
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 <file>..." to update what will be committed)
|
||||
(use "git restore <file>..." 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 <file>..." 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 <file>..." to update what will be committed)
|
||||
(use "git restore <file>..." 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 <file>..." 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
|
Loading…
Reference in New Issue
Block a user