Skip to content

Commit 459fb53

Browse files
committed
Clean-up adding_lints.md
1 parent 8cdd75c commit 459fb53

File tree

1 file changed

+49
-50
lines changed

1 file changed

+49
-50
lines changed

doc/adding_lints.md

Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## Adding a new lint
1+
# Adding a new lint
22

33
You are probably here because you want to add a new lint to Clippy. If this is
44
the first time you're contributing to Clippy, this document guides you through
@@ -25,14 +25,14 @@ because that's clearly a non-descriptive name.
2525
- [PR Checklist](#pr-checklist)
2626
- [Cheatsheet](#cheatsheet)
2727

28-
### Setup
28+
## Setup
2929

3030
When working on Clippy, you will need the current git master version of rustc,
3131
which can change rapidly. Make sure you're working near rust-clippy's master,
3232
and use the `setup-toolchain.sh` script to configure the appropriate toolchain
3333
for the Clippy directory.
3434

35-
### Getting Started
35+
## Getting Started
3636

3737
There is a bit of boilerplate code that needs to be set up when creating a new
3838
lint. Fortunately, you can use the clippy dev tools to handle this for you. We
@@ -45,7 +45,7 @@ two files: `tests/ui/foo_functions.rs` and `clippy_lints/src/foo_functions.rs`,
4545
as well as run `cargo dev update_lints` to register the new lint. Next, we'll
4646
open up these files and add our lint!
4747

48-
### Testing
48+
## Testing
4949

5050
Let's write some tests first that we can execute while we iterate on our lint.
5151

@@ -88,12 +88,10 @@ fn main() {
8888
let a = A;
8989
a.foo();
9090
}
91-
9291
```
9392

94-
Now we can run the test with `TESTNAME=foo_functions cargo uitest`.
95-
Currently this test will fail. If you go through the output you will see that we
96-
are told that `clippy::foo_functions` is an unknown lint, which is expected.
93+
Now we can run the test with `TESTNAME=foo_functions cargo uitest`,
94+
currently this test is meaningless though.
9795

9896
While we are working on implementing our lint, we can keep running the UI
9997
test. That allows us to check if the output is turning into what we want.
@@ -105,7 +103,7 @@ every time before running `tests/ui/update-all-references.sh`.
105103
Running `TESTNAME=foo_functions cargo uitest` should pass then. When we commit
106104
our lint, we need to commit the generated `.stderr` files, too.
107105

108-
### Rustfix tests
106+
## Rustfix tests
109107

110108
If the lint you are working on is making use of structured suggestions, the
111109
test file should include a `// run-rustfix` comment at the top. This will
@@ -116,13 +114,13 @@ test file and compare that to the contents of a `.fixed` file.
116114
Use `tests/ui/update-all-references.sh` to automatically generate the
117115
`.fixed` file after running the tests.
118116

119-
### Edition 2018 tests
117+
## Edition 2018 tests
120118

121119
Some features require the 2018 edition to work (e.g. `async_await`), but
122120
compile-test tests run on the 2015 edition by default. To change this behavior
123-
add `// compile-flags: --edition 2018` at the top of the test file.
121+
add `// edition:2018` at the top of the test file (note that it's space-sensitive).
124122

125-
### Testing manually
123+
## Testing manually
126124

127125
Manually testing against an example file can be useful if you have added some
128126
`println!`s and the test suite output becomes unreadable. To try Clippy with
@@ -131,7 +129,7 @@ clippy-driver -- -L ./target/debug input.rs` from the working copy root.
131129

132130
With tests in place, let's have a look at implementing our lint now.
133131

134-
### Lint declaration
132+
## Lint declaration
135133

136134
Let's start by opening the new file created in the `clippy_lints` crate
137135
at `clippy_lints/src/foo_functions.rs`. That's the crate where all the
@@ -140,7 +138,7 @@ lint code is. This file has already imported some initial things we will need:
140138
```rust
141139
use rustc_lint::{EarlyLintPass, EarlyContext};
142140
use rustc_session::{declare_lint_pass, declare_tool_lint};
143-
use syntax::ast::*;
141+
use rustc_ast::ast::*;
144142
```
145143

146144
The next step is to update the lint declaration. Lints are declared using the
@@ -167,8 +165,8 @@ declare_clippy_lint! {
167165
```
168166

169167
* The section of lines prefixed with `///` constitutes the lint documentation
170-
section. This is the default documentation style and will be displayed at
171-
https://rust-lang.github.io/rust-clippy/master/index.html.
168+
section. This is the default documentation style and will be displayed
169+
[like this][example_lint_page].
172170
* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the [lint naming
173171
guidelines][lint_naming] here when naming your lint. In short, the name should
174172
state the thing that is being checked for and read well when used with
@@ -199,14 +197,12 @@ automate everything. We will have to register our lint pass manually in the
199197
`register_plugins` function in `clippy_lints/src/lib.rs`:
200198

201199
```rust
202-
store.register_early_pass(box foo_functions::FooFunctions);
200+
store.register_early_pass(|| box foo_functions::FooFunctions);
203201
```
204202

205-
This should fix the `unknown clippy lint: clippy::foo_functions` error that we
206-
saw when we executed our tests the first time. The next decision we have to make
207-
is which lint pass our lint is going to need.
203+
[example lint page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
208204

209-
### Lint passes
205+
## Lint passes
210206

211207
Writing a lint that only checks for the name of a function means that we only
212208
have to deal with the AST and don't have to deal with the type system at all.
@@ -224,7 +220,7 @@ Since we don't need type information for checking the function name, we used
224220
`--pass=early` when running the new lint automation and all the imports were
225221
added accordingly.
226222

227-
### Emitting a lint
223+
## Emitting a lint
228224

229225
With UI tests and the lint declaration in place, we can start working on the
230226
implementation of the lint logic.
@@ -233,7 +229,7 @@ Let's start by implementing the `EarlyLintPass` for our `FooFunctions`:
233229

234230
```rust
235231
impl EarlyLintPass for FooFunctions {
236-
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
232+
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
237233
// TODO: Emit lint here
238234
}
239235
}
@@ -255,7 +251,7 @@ automatically. This is how it looks:
255251

256252
```rust
257253
impl EarlyLintPass for FooFunctions {
258-
fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
254+
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
259255
span_lint_and_help(
260256
cx,
261257
FOO_FUNCTIONS,
@@ -269,20 +265,20 @@ impl EarlyLintPass for FooFunctions {
269265

270266
Running our UI test should now produce output that contains the lint message.
271267

272-
### Adding the lint logic
268+
## Adding the lint logic
273269

274270
Writing the logic for your lint will most likely be different from our example,
275271
so this section is kept rather short.
276272

277273
Using the [`check_fn`][check_fn] method gives us access to [`FnKind`][fn_kind]
278-
that has two relevant variants for us `FnKind::ItemFn` and `FnKind::Method`.
279-
Both provide access to the name of the function/method via an [`Ident`][ident].
274+
that has the `FnKind::Fn` variant. It provides access to the name of the
275+
function/method via an [`Ident`][ident].
280276

281277
With that we can expand our `check_fn` method to:
282278

283279
```rust
284280
impl EarlyLintPass for FooFunctions {
285-
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
281+
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
286282
if is_foo_fn(fn_kind) {
287283
span_lint_and_help(
288284
cx,
@@ -307,9 +303,11 @@ In our example, `is_foo_fn` looks like:
307303

308304
fn is_foo_fn(fn_kind: FnKind<'_>) -> bool {
309305
match fn_kind {
310-
FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) => {
311-
ident.name == "foo"
312-
},
306+
FnKind::Fn(_, ident, ..) => {
307+
// check if `fn` name is `foo`
308+
ident.name.as_str() == "foo"
309+
}
310+
// ignore closures
313311
FnKind::Closure(..) => false
314312
}
315313
}
@@ -325,13 +323,14 @@ implementation is not violating any Clippy lints itself.
325323
That should be it for the lint implementation. Running `cargo test` should now
326324
pass.
327325

328-
### Author lint
326+
## Author lint
329327

330328
If you have trouble implementing your lint, there is also the internal `author`
331329
lint to generate Clippy code that detects the offending pattern. It does not
332330
work for all of the Rust syntax, but can give a good starting point.
333331

334-
The quickest way to use it, is the [Rust playground: play.rust-lang.org][Play].
332+
The quickest way to use it, is the
333+
[Rust playground: play.rust-lang.org][author_example].
335334
Put the code you want to lint into the editor and add the `#[clippy::author]`
336335
attribute above the item. Then run Clippy via `Tools -> Clippy` and you should
337336
see the generated code in the output below.
@@ -341,7 +340,7 @@ see the generated code in the output below.
341340
If the command was executed successfully, you can copy the code over to where
342341
you are implementing your lint.
343342

344-
### Documentation
343+
## Documentation
345344

346345
The final thing before submitting our PR is to add some documentation to our
347346
lint declaration.
@@ -374,7 +373,7 @@ declare_clippy_lint! {
374373
Once your lint is merged, this documentation will show up in the [lint
375374
list][lint_list].
376375

377-
### Running rustfmt
376+
## Running rustfmt
378377

379378
[Rustfmt](https://github.com/rust-lang/rustfmt) is a tool for formatting Rust
380379
code according to style guidelines. Your code has to be formatted by `rustfmt`
@@ -389,13 +388,13 @@ rustup component add rustfmt --toolchain=nightly
389388
Use `cargo dev fmt` to format the whole codebase. Make sure that `rustfmt` is
390389
installed for the nightly toolchain.
391390

392-
### Debugging
391+
## Debugging
393392

394-
If you want to debug parts of your lint implementation, you can use the `dbg!`
393+
If you want to debug parts of your lint implementation, you can use the [`dbg!`]
395394
macro anywhere in your code. Running the tests should then include the debug
396395
output in the `stdout` part.
397396

398-
### PR Checklist
397+
## PR Checklist
399398

400399
Before submitting your PR make sure you followed all of the basic requirements:
401400

@@ -408,7 +407,7 @@ Before submitting your PR make sure you followed all of the basic requirements:
408407
- [ ] Added lint documentation
409408
- [ ] Run `cargo dev fmt`
410409

411-
### Cheatsheet
410+
## Cheatsheet
412411

413412
Here are some pointers to things you are likely going to need for every lint:
414413

@@ -426,38 +425,38 @@ Here are some pointers to things you are likely going to need for every lint:
426425
For `EarlyLintPass` lints:
427426

428427
* [`EarlyLintPass`][early_lint_pass]
429-
* [`syntax::ast`][ast]
428+
* [`rustc_ast::ast`][ast]
430429

431430
For `LateLintPass` lints:
432431

433432
* [`LateLintPass`][late_lint_pass]
434433
* [`Ty::TyKind`][ty]
435434

436-
437435
While most of Clippy's lint utils are documented, most of rustc's internals lack
438436
documentation currently. This is unfortunate, but in most cases you can probably
439437
get away with copying things from existing similar lints. If you are stuck,
440-
don't hesitate to ask on Discord, IRC or in the issue/PR.
438+
don't hesitate to ask on [Discord] or in the issue/PR.
441439

442440
[lint_list]: https://rust-lang.github.io/rust-clippy/master/index.html
443441
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
444442
[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/bd23cb89ec0ea63403a17d3fc5e50c88e38dd54f/clippy_lints/src/lib.rs#L43
445443
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/a71acac1da7eaf667ab90a1d65d10e5cc4b80191/clippy_lints/src/lib.rs#L39
446-
[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.EarlyLintPass.html#method.check_fn
447-
[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.EarlyLintPass.html
448-
[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.LateLintPass.html
449-
[fn_kind]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/visit/enum.FnKind.html
444+
[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn
445+
[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
446+
[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
447+
[fn_kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html
450448
[diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
451449
[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs
452-
[ident]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/source_map/symbol/struct.Ident.html
450+
[ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html
453451
[span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
454452
[applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
455453
[if_chain]: https://docs.rs/if_chain/*/if_chain/
456454
[ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/sty/index.html
457-
[ast]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/index.html
455+
[ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html
458456
[from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
459457
[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/fn.in_external_macro.html
460-
[play]: https://play.rust-lang.org
461-
[author_example]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f093b986e80ad62f3b67a1f24f5e66e2
458+
[author_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55
462459
[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
463460
[nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/
461+
[Discord]: https://discord.gg/rust-lang
462+
[`dbg`!]: https://doc.rust-lang.org/std/macro.dbg.html

0 commit comments

Comments
 (0)