Skip to content

Commit 87d1487

Browse files
committed
Auto merge of rust-lang#10595 - blyxyas:book-define_lints, r=flip1995
Clippy Book Chapter Updates Reborn: Defining Lints Revival of rust-lang#9659, I've made a few changes (mainly ones from reviews from rust-lang#9426, like removing mid-section storytelling) and some re-writes. The goal of the project would be to slowly re-write the Clippy book (only chapters that need it) to more up-to-date style. ## Notes - Things like `git status` commands have changed, we need to make sure that they're correct. - As this is a team-wide effort, I would please ask anyone and everyone to read it and give your opinion. - To talk about the whole project, please use the tracking issue for the project rust-lang#10597 (It also contains a timeline, discussions and more information) --- changelog: Add a new "Defining lints" chapter to the book r? `@flip1995`
2 parents 710db18 + 783c119 commit 87d1487

File tree

2 files changed

+206
-0
lines changed

2 files changed

+206
-0
lines changed

book/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- [Development](development/README.md)
1414
- [Basics](development/basics.md)
1515
- [Adding Lints](development/adding_lints.md)
16+
- [Defining Lints](development/defining_lints.md)
1617
- [Lint Passes](development/lint_passes.md)
1718
- [Type Checking](development/type_checking.md)
1819
- [Macro Expansions](development/macro_expansions.md)
+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Define New Lints
2+
3+
The first step in the journey of a new lint is the definition
4+
and registration of the lint in Clippy's codebase.
5+
We can use the Clippy dev tools to handle this step since setting up the
6+
lint involves some boilerplate code.
7+
8+
#### Lint types
9+
10+
A lint type is the category of items and expressions in which your lint focuses on.
11+
12+
As of the writing of this documentation update, there are 12 _types_ of lints
13+
besides the numerous standalone lints living under `clippy_lints/src/`:
14+
15+
- `cargo`
16+
- `casts`
17+
- `functions`
18+
- `loops`
19+
- `matches`
20+
- `methods`
21+
- `misc_early`
22+
- `operators`
23+
- `transmute`
24+
- `types`
25+
- `unit_types`
26+
- `utils / internal` (Clippy internal lints)
27+
28+
These types group together lints that share some common behaviors. For instance,
29+
`functions` groups together lints that deal with some aspects of functions in
30+
Rust, like definitions, signatures and attributes.
31+
32+
For more information, feel free to compare the lint files under any category
33+
with [All Clippy lints][all_lints] or ask one of the maintainers.
34+
35+
## Lint name
36+
37+
A good lint name is important, make sure to check the [lint naming
38+
guidelines][lint_naming]. Don't worry, if the lint name doesn't fit, a Clippy
39+
team member will alert you in the PR process.
40+
41+
---
42+
43+
We'll name our example lint that detects functions named "foo" `foo_functions`.
44+
Check the [lint naming guidelines][lint_naming] to see why this name makes
45+
sense.
46+
47+
## Add and Register the Lint
48+
49+
Now that a name is chosen, we shall register `foo_functions` as a lint to the
50+
codebase. There are two ways to register a lint.
51+
52+
### Standalone
53+
54+
If you believe that this new lint is a standalone lint (that doesn't belong to
55+
any specific [type](#lint-types) like `functions` or `loops`), you can run the
56+
following command in your Clippy project:
57+
58+
```sh
59+
$ cargo dev new_lint --name=lint_name --pass=late --category=pedantic
60+
```
61+
62+
There are two things to note here:
63+
64+
1. `--pass`: We set `--pass=late` in this command to do a late lint pass. The
65+
alternative is an `early` lint pass. We will discuss this difference in a
66+
later chapter.
67+
<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
68+
2. `--category`: If not provided, the `category` of this new lint will default
69+
to `nursery`.
70+
71+
The `cargo dev new_lint` command will create a new file:
72+
`clippy_lints/src/foo_functions.rs` as well as [register the
73+
lint](#lint-registration).
74+
75+
Overall, you should notice that the following files are modified or created:
76+
77+
```sh
78+
$ git status
79+
On branch foo_functions
80+
Changes not staged for commit:
81+
(use "git add <file>..." to update what will be committed)
82+
(use "git restore <file>..." to discard changes in working directory)
83+
modified: CHANGELOG.md
84+
modified: clippy_lints/src/lib.register_lints.rs
85+
modified: clippy_lints/src/lib.register_pedantic.rs
86+
modified: clippy_lints/src/lib.rs
87+
88+
Untracked files:
89+
(use "git add <file>..." to include in what will be committed)
90+
clippy_lints/src/foo_functions.rs
91+
tests/ui/foo_functions.rs
92+
```
93+
94+
95+
### Specific Type
96+
97+
> **Note**: Lint types are listed in the ["Lint types"](#lint-types) section
98+
99+
If you believe that this new lint belongs to a specific type of lints,
100+
you can run `cargo dev new_lint` with a `--type` option.
101+
102+
Since our `foo_functions` lint is related to function calls, one could
103+
argue that we should put it into a group of lints that detect some behaviors
104+
of functions, we can put it in the `functions` group.
105+
106+
Let's run the following command in your Clippy project:
107+
108+
```sh
109+
$ cargo dev new_lint --name=foo_functions --type=functions --category=pedantic
110+
```
111+
112+
This command will create, among other things, a new file:
113+
`clippy_lints/src/{type}/foo_functions.rs`.
114+
In our case, the path will be `clippy_lints/src/functions/foo_functions.rs`.
115+
116+
Notice how this command has a `--type` flag instead of `--pass`. Unlike a standalone
117+
definition, this lint won't be registered in the traditional sense. Instead, you will
118+
call your lint from within the type's lint pass, found in `clippy_lints/src/{type}/mod.rs`.
119+
120+
A _type_ is just the name of a directory in `clippy_lints/src`, like `functions` in
121+
the example command. Clippy groups together some lints that share common behaviors,
122+
so if your lint falls into one, it would be best to add it to that type.
123+
124+
Overall, you should notice that the following files are modified or created:
125+
126+
```sh
127+
$ git status
128+
On branch foo_functions
129+
Changes not staged for commit:
130+
(use "git add <file>..." to update what will be committed)
131+
(use "git restore <file>..." to discard changes in working directory)
132+
modified: CHANGELOG.md
133+
modified: clippy_lints/src/declared_lints.rs
134+
modified: clippy_lints/src/functions/mod.rs
135+
136+
Untracked files:
137+
(use "git add <file>..." to include in what will be committed)
138+
clippy_lints/src/functions/foo_functions.rs
139+
tests/ui/foo_functions.rs
140+
```
141+
142+
143+
## The `define_clippy_lints` macro
144+
145+
After `cargo dev new_lint`, you should see a macro with the name
146+
`define_clippy_lints`. It will be in the same file if you defined a standalone
147+
lint, and it will be in `mod.rs` if you defined a type-specific lint.
148+
149+
The macro looks something like this:
150+
151+
```rust
152+
declare_clippy_lint! {
153+
/// ### What it does
154+
///
155+
/// // Describe here what does the lint do.
156+
///
157+
/// Triggers when detects...
158+
///
159+
/// ### Why is this bad?
160+
///
161+
/// // Describe why this pattern would be bad
162+
///
163+
/// It can lead to...
164+
///
165+
/// ### Example
166+
/// ```rust
167+
/// // example code where clippy issues a warning
168+
/// ```
169+
/// Use instead:
170+
/// ```rust
171+
/// // example code which does not raise clippy warning
172+
/// ```
173+
#[clippy::version = "1.70.0"] // <- In which version was this implemented, keep it up to date!
174+
pub LINT_NAME, // <- The lint name IN_ALL_CAPS
175+
pedantic, // <- The lint group
176+
"default lint description" // <- A lint description, e.g. "A function has an unit return type."
177+
}
178+
```
179+
180+
## Lint registration
181+
182+
If we run the `cargo dev new_lint` command for a new lint, the lint will be
183+
automatically registered and there is nothing more to do.
184+
185+
However, sometimes we might want to declare a new lint by hand. In this case,
186+
we'd use `cargo dev update_lints` command afterwards.
187+
188+
When a lint is manually declared, we might need to register the lint pass
189+
manually in the `register_plugins` function in `clippy_lints/src/lib.rs`:
190+
191+
```rust
192+
store.register_late_pass(|_| Box::new(foo_functions::FooFunctions));
193+
```
194+
195+
As you might have guessed, where there's something late, there is something
196+
early: in Clippy there is a `register_early_pass` method as well. More on early
197+
vs. late passes in a later chapter.
198+
<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
199+
200+
Without a call to one of `register_early_pass` or `register_late_pass`, the lint
201+
pass in question will not be run.
202+
203+
204+
[all_lints]: https://rust-lang.github.io/rust-clippy/master/
205+
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints

0 commit comments

Comments
 (0)