Skip to content

Commit 0049816

Browse files
committed
Auto merge of #10622 - blyxyas:book-lint_passes, r=llogiq
Clippy Book Chapter Updates Reborn: Lint Passes This PR adds a new chapter to the book: "Lint passes". No major changes apart from some re-phrasing, fixing typos... etc. ## Notes - Requires #10595 to be merged before this one (Or else, a link will be broken). - To talk about the whole project, please use the tracking issue for the project #10597 (It also contains a timeline, discussions and more information) changelog: Add a new "Lint passes" chapter to the book r? `@flip1995`
2 parents b2edd42 + b473267 commit 0049816

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

book/src/development/lint_passes.md

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Lint passes
2+
3+
Before working on the logic of a new lint, there is an important decision
4+
that every Clippy developers must make: to use
5+
[`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass].
6+
7+
In short, the `LateLintPass` has access to type and symbol information while the
8+
`EarlyLintPass` doesn't. If you don't need access to type information, use the
9+
`EarlyLintPass`.
10+
11+
Let us expand on these two traits more below.
12+
13+
## `EarlyLintPass`
14+
15+
If you examine the documentation on [`EarlyLintPass`][early_lint_pass] closely,
16+
you'll see that every method defined for this trait utilizes a
17+
[`EarlyContext`][early_context]. In `EarlyContext`'s documentation, it states:
18+
19+
> Context for lint checking of the AST, after expansion, before lowering to HIR.
20+
21+
Voilà. `EarlyLintPass` works only on the Abstract Syntax Tree (AST) level.
22+
And AST is generated during the [lexing and parsing][lexing_and_parsing] phase
23+
of code compilation. Therefore, it doesn't know what a symbol means or information about types, and it should
24+
be our trait choice for a new lint if the lint only deals with syntax-related issues.
25+
26+
While linting speed has not been a concern for Clippy,
27+
the `EarlyLintPass` is faster, and it should be your choice
28+
if you know for sure a lint does not need type information.
29+
30+
As a reminder, run the following command to generate boilerplate for lints
31+
that use `EarlyLintPass`:
32+
33+
```sh
34+
$ cargo dev new_lint --name=<your_new_lint> --pass=early --category=<your_category_choice>
35+
```
36+
37+
### Example for `EarlyLintPass`
38+
39+
Take a look at the following code:
40+
41+
```rust
42+
let x = OurUndefinedType;
43+
x.non_existing_method();
44+
```
45+
46+
From the AST perspective, both lines are "grammatically" correct.
47+
The assignment uses a `let` and ends with a semicolon. The invocation
48+
of a method looks fine, too. As programmers, we might raise a few
49+
questions already, but the parser is okay with it. This is what we
50+
mean when we say `EarlyLintPass` deals with only syntax on the AST level.
51+
52+
Alternatively, think of the `foo_functions` lint we mentioned in
53+
[define new lints](define_lints.md#name-the-lint) chapter.
54+
55+
We want the `foo_functions` lint to detect functions with `foo` as their name.
56+
Writing a lint that only checks for the name of a function means that we only
57+
work with the AST and don't have to access the type system at all (the type system is where
58+
`LateLintPass` comes into the picture).
59+
60+
## `LateLintPass`
61+
62+
In contrast to `EarlyLintPass`, `LateLintPass` contains type information.
63+
64+
If you examine the documentation on [`LateLintPass`][late_lint_pass] closely,
65+
you see that every method defined in this trait utilizes a
66+
[`LateContext`][late_context].
67+
68+
In `LateContext`'s documentation we will find methods that
69+
deal with type-checking, which do not exist in `EarlyContext`, such as:
70+
71+
- [`maybe_typeck_results`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#method.maybe_typeck_results)
72+
- [`typeck_results`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#method.typeck_results)
73+
74+
### Example for `LateLintPass`
75+
76+
Let us take a look with the following example:
77+
78+
```rust
79+
let x = OurUndefinedType;
80+
x.non_existing_method();
81+
```
82+
83+
These two lines of code are syntactically correct code from the perspective
84+
of the AST. We have an assignment and invoke a method on the variable that
85+
is of a type. Grammatically, everything is in order for the parser.
86+
87+
However, going down a level and looking at the type information,
88+
the compiler will notice that both `OurUndefinedType` and `non_existing_method()`
89+
**are undefined**.
90+
91+
As Clippy developers, to access such type information, we must implement
92+
`LateLintPass` on our lint.
93+
When you browse through Clippy's lints, you will notice that almost every lint
94+
is implemented in a `LateLintPass`, specifically because we often need to check
95+
not only for syntactic issues but also type information.
96+
97+
Another limitation of the `EarlyLintPass` is that the nodes are only identified
98+
by their position in the AST. This means that you can't just get an `id` and
99+
request a certain node. For most lints that is fine, but we have some lints
100+
that require the inspection of other nodes, which is easier at the HIR level.
101+
In these cases, `LateLintPass` is the better choice.
102+
103+
As a reminder, run the following command to generate boilerplate for lints
104+
that use `LateLintPass`:
105+
106+
```sh
107+
$ cargo dev new_lint --name=<your_new_lint> --pass=late --category=<your_category_choice>
108+
```
109+
110+
## Additional Readings for Beginners
111+
112+
If a dear reader of this documentation has never taken a class on compilers
113+
and interpreters, it might be confusing as to why AST level deals with only
114+
the language's syntax. And some readers might not even understand what lexing,
115+
parsing, and AST mean.
116+
117+
This documentation serves by no means as a crash course on compilers or language design.
118+
And for details specifically related to Rust, the [Rustc Development Guide][rustc_dev_guide]
119+
is a far better choice to peruse.
120+
121+
The [Syntax and AST][ast] chapter and the [High-Level IR][hir] chapter are
122+
great introduction to the concepts mentioned in this chapter.
123+
124+
Some readers might also find the [introductory chapter][map_of_territory] of
125+
Robert Nystrom's _Crafting Interpreters_ a helpful overview of compiled and
126+
interpreted languages before jumping back to the Rustc guide.
127+
128+
[ast]: https://rustc-dev-guide.rust-lang.org/syntax-intro.html
129+
[early_context]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.EarlyContext.html
130+
[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
131+
[hir]: https://rustc-dev-guide.rust-lang.org/hir.html
132+
[late_context]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html
133+
[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
134+
[lexing_and_parsing]: https://rustc-dev-guide.rust-lang.org/overview.html#lexing-and-parsing
135+
[rustc_dev_guide]: https://rustc-dev-guide.rust-lang.org/
136+
[map_of_territory]: https://craftinginterpreters.com/a-map-of-the-territory.html

0 commit comments

Comments
 (0)