Skip to content

Commit e496a6f

Browse files
committed
Copy from CONTRIBUTING.md: author lint, rustfix tests, rustfmt
And adapt the wording a bit so that it fits in the overall guide.
1 parent 31b6284 commit e496a6f

File tree

1 file changed

+81
-4
lines changed

1 file changed

+81
-4
lines changed

doc/adding_lints.md

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,25 @@ creating an example lint from scratch.
77
To get started, we will create a lint that detects functions called `foo`,
88
because that's clearly a non-descriptive name.
99

10+
* [Setup](#Setup)
1011
* [Testing](#Testing)
12+
* [Rustfix tests](#Rustfix-tests)
1113
* [Lint declaration](#Lint-declaration)
1214
* [Lint passes](#Lint-passes)
1315
* [Emitting a lint](#Emitting-a-lint)
1416
* [Adding the lint logic](#Adding-the-lint-logic)
1517
* [Documentation](#Documentation)
18+
* [Running rustfmt](#Running-rustfmt)
1619
* [Debugging](#Debugging)
1720
* [PR Checklist](#PR-Checklist)
1821
* [Cheatsheet](#Cheatsheet)
1922

23+
### Setup
24+
25+
Clippy depends on the current git master version of rustc, which can change rapidly. Make sure you're
26+
working near rust-clippy's master, and use the `setup-toolchain.sh` script to configure the appropriate
27+
toolchain for this directory.
28+
2029
### Testing
2130

2231
Let's write some tests first that we can execute while we iterate on our lint.
@@ -75,7 +84,25 @@ Once you are satisfied with the output, you need to run
7584
Running `TESTNAME=ui/foo_functions cargo uitest` should pass then. When you
7685
commit your lint, be sure to commit the `*.stderr` files, too.
7786

78-
Let's have a look at implementing our lint now.
87+
### Rustfix tests
88+
89+
If the lint you are working on is making use of structured suggestions, the
90+
test file should include a `// run-rustfix` comment at the top. This will
91+
additionally run [rustfix](https://github.com/rust-lang-nursery/rustfix) for
92+
that test. Rustfix will apply the suggestions from the lint to the code of the
93+
test file and compare that to the contents of a `.fixed` file.
94+
95+
Use `tests/ui/update-all-references.sh` to automatically generate the
96+
`.fixed` file after running `cargo test`.
97+
98+
With tests in place, let's have a look at implementing our lint now.
99+
100+
### Testing manually
101+
102+
Manually testing against an example file is useful if you have added some
103+
`println!`s and test suite output becomes unreadable. To try Clippy with your
104+
local modifications, run `env CLIPPY_TESTS=true cargo run --bin clippy-driver -- -L ./target/debug input.rs`
105+
from the working copy root.
79106

80107
### Lint declaration
81108

@@ -278,7 +305,44 @@ impl LintPass for Pass { /* .. */ }
278305
```
279306

280307
That should be it for the lint implementation. Running `cargo test` should now
281-
pass and we can finish up our work by adding some documentation.
308+
pass.
309+
310+
### Author lint
311+
312+
If you have trouble implementing your lint, there is also the internal `author`
313+
lint to generate Clippy code that detects the offending pattern. It does not
314+
work for all of the Rust syntax, but can give a good starting point.
315+
316+
First, create a new UI test file in the `tests/ui/` directory with the pattern
317+
you want to match:
318+
319+
```rust
320+
// ./tests/ui/my_lint.rs
321+
fn main() {
322+
#[clippy::author]
323+
let arr: [i32; 1] = [7]; // Replace line with the code you want to match
324+
}
325+
```
326+
327+
Now you run `TESTNAME=ui/my_lint cargo uitest` to produce a `.stdout` file with
328+
the generated code:
329+
330+
```rust
331+
// ./tests/ui/my_lint.stdout
332+
333+
if_chain! {
334+
if let ExprKind::Array(ref elements) = stmt.node;
335+
if elements.len() == 1;
336+
if let ExprKind::Lit(ref lit) = elements[0].node;
337+
if let LitKind::Int(7, _) = lit.node;
338+
then {
339+
// report your lint here
340+
}
341+
}
342+
```
343+
344+
If the command was executed successfully, you can copy the code over to where
345+
you are implementing your lint.
282346

283347
### Documentation
284348

@@ -309,6 +373,19 @@ declare_clippy_lint! { /* ... */ }
309373
Once your lint is merged, this documentation will show up in the [lint
310374
list][lint_list].
311375

376+
### Running rustfmt
377+
378+
[Rustfmt](https://github.com/rust-lang/rustfmt) is a tool for formatting Rust code according
379+
to style guidelines. Your code has to be formatted by `rustfmt` before a PR can be merged.
380+
381+
It can be installed via `rustup`:
382+
383+
```bash
384+
rustup component add rustfmt
385+
```
386+
387+
Use `cargo fmt --all` to format the whole codebase.
388+
312389
### Debugging
313390

314391
If you want to debug parts of your lint implementation, you can use the `dbg!`
@@ -317,7 +394,7 @@ output in the `stdout` part.
317394

318395
### PR Checklist
319396

320-
TODO: Prose
397+
Before submitting your PR make sure you followed all of the basic requirements:
321398

322399
- [ ] Followed [lint naming conventions][lint_naming]
323400
- [ ] Added passing UI tests (including committed `.stderr` file)
@@ -329,7 +406,7 @@ TODO: Prose
329406
Here are some pointers to things you are likely going to need for every lint:
330407

331408
* [Clippy utils][utils] - Various helper functions. Maybe the function you need
332-
is already in here. (`implements_trait`, `match_path`, `snippet`, etc)
409+
is already in here (`implements_trait`, `match_path`, `snippet`, etc)
333410
* [Clippy diagnostics][diagnostics]
334411
* [The `if_chain` macro][if_chain]
335412
* [`in_macro`][in_macro] and [`in_external_macro`][in_external_macro]

0 commit comments

Comments
 (0)