about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-14 17:04:54 +0000
committerbors <bors@rust-lang.org>2023-04-14 17:04:54 +0000
commit004981647f6f7bd2e70808651e897b1e6b719bb4 (patch)
tree4f49938b9876ad8b5dc40c2f64a5ef12f2374c76
parentb2edd42b24307d4ad931117642380872ebd38372 (diff)
parentb4732679fc63b3c66d830c3b7edf8bcbb84aff12 (diff)
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`
-rw-r--r--book/src/development/lint_passes.md136
1 files changed, 136 insertions, 0 deletions
diff --git a/book/src/development/lint_passes.md b/book/src/development/lint_passes.md
new file mode 100644
index 00000000000..058b9fa3233
--- /dev/null
+++ b/book/src/development/lint_passes.md
@@ -0,0 +1,136 @@
+# Lint passes
+
+Before working on the logic of a new lint, there is an important decision
+that every Clippy developers must make: to use
+[`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass].
+
+In short, the `LateLintPass` has access to type and symbol information while the
+`EarlyLintPass` doesn't. If you don't need access to type information, use the
+`EarlyLintPass`.
+
+Let us expand on these two traits more below.
+
+## `EarlyLintPass`
+
+If you examine the documentation on [`EarlyLintPass`][early_lint_pass] closely,
+you'll see that every method defined for this trait utilizes a
+[`EarlyContext`][early_context]. In `EarlyContext`'s documentation, it states:
+
+> Context for lint checking of the AST, after expansion, before lowering to HIR.
+
+VoilĂ . `EarlyLintPass` works only on the Abstract Syntax Tree (AST) level.
+And AST is generated during the [lexing and parsing][lexing_and_parsing] phase
+of code compilation. Therefore, it doesn't know what a symbol means or information about types, and it should
+be our trait choice for a new lint if the lint only deals with syntax-related issues.
+
+While linting speed has not been a concern for Clippy,
+the `EarlyLintPass` is faster, and it should be your choice
+if you know for sure a lint does not need type information.
+
+As a reminder, run the following command to generate boilerplate for lints
+that use `EarlyLintPass`:
+
+```sh
+$ cargo dev new_lint --name=<your_new_lint> --pass=early --category=<your_category_choice>
+```
+
+### Example for `EarlyLintPass`
+
+Take a look at the following code:
+
+```rust
+let x = OurUndefinedType;
+x.non_existing_method();
+```
+
+From the AST perspective, both lines are "grammatically" correct.
+The assignment uses a `let` and ends with a semicolon. The invocation
+of a method looks fine, too. As programmers, we might raise a few
+questions already, but the parser is okay with it. This is what we
+mean when we say `EarlyLintPass` deals with only syntax on the AST level.
+
+Alternatively, think of the `foo_functions` lint we mentioned in
+[define new lints](define_lints.md#name-the-lint) chapter.
+
+We want the `foo_functions` lint to detect functions with `foo` as their name.
+Writing a lint that only checks for the name of a function means that we only
+work with the AST and don't have to access the type system at all (the type system is where
+`LateLintPass` comes into the picture).
+
+## `LateLintPass`
+
+In contrast to `EarlyLintPass`, `LateLintPass` contains type information.
+
+If you examine the documentation on [`LateLintPass`][late_lint_pass] closely,
+you see that every method defined in this trait utilizes a
+[`LateContext`][late_context].
+
+In `LateContext`'s documentation we will find methods that
+deal with type-checking, which do not exist in `EarlyContext`, such as:
+
+- [`maybe_typeck_results`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#method.maybe_typeck_results)
+- [`typeck_results`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#method.typeck_results)
+
+### Example for `LateLintPass`
+
+Let us take a look with the following example:
+
+```rust
+let x = OurUndefinedType;
+x.non_existing_method();
+```
+
+These two lines of code are syntactically correct code from the perspective
+of the AST. We have an assignment and invoke a method on the variable that
+is of a type. Grammatically, everything is in order for the parser.
+
+However, going down a level and looking at the type information,
+the compiler will notice that both `OurUndefinedType` and `non_existing_method()`
+**are undefined**.
+
+As Clippy developers, to access such type information, we must implement
+`LateLintPass` on our lint.
+When you browse through Clippy's lints, you will notice that almost every lint
+is implemented in a `LateLintPass`, specifically because we often need to check
+not only for syntactic issues but also type information.
+
+Another limitation of the `EarlyLintPass` is that the nodes are only identified
+by their position in the AST. This means that you can't just get an `id` and
+request a certain node. For most lints that is fine, but we have some lints
+that require the inspection of other nodes, which is easier at the HIR level.
+In these cases, `LateLintPass` is the better choice.
+
+As a reminder, run the following command to generate boilerplate for lints
+that use `LateLintPass`:
+
+```sh
+$ cargo dev new_lint --name=<your_new_lint> --pass=late --category=<your_category_choice>
+```
+
+## Additional Readings for Beginners
+
+If a dear reader of this documentation has never taken a class on compilers
+and interpreters, it might be confusing as to why AST level deals with only
+the language's syntax. And some readers might not even understand what lexing,
+parsing, and AST mean.
+
+This documentation serves by no means as a crash course on compilers or language design.
+And for details specifically related to Rust, the [Rustc Development Guide][rustc_dev_guide]
+is a far better choice to peruse.
+
+The [Syntax and AST][ast] chapter and the [High-Level IR][hir] chapter are
+great introduction to the concepts mentioned in this chapter.
+
+Some readers might also find the [introductory chapter][map_of_territory] of
+Robert Nystrom's _Crafting Interpreters_ a helpful overview of compiled and
+interpreted languages before jumping back to the Rustc guide.
+
+[ast]: https://rustc-dev-guide.rust-lang.org/syntax-intro.html
+[early_context]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.EarlyContext.html
+[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
+[hir]: https://rustc-dev-guide.rust-lang.org/hir.html
+[late_context]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html
+[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
+[lexing_and_parsing]: https://rustc-dev-guide.rust-lang.org/overview.html#lexing-and-parsing
+[rustc_dev_guide]: https://rustc-dev-guide.rust-lang.org/
+[map_of_territory]: https://craftinginterpreters.com/a-map-of-the-territory.html