Formatting and minor wording fixes

This commit is contained in:
Philipp Krones 2023-08-18 19:55:01 +02:00
parent f76615a7ac
commit 9b8b83556b
No known key found for this signature in database
GPG Key ID: 1CA0DF2AF59D68A5

View File

@ -1,17 +1,18 @@
# Emitting a lint # Emitting a lint
Once we have [defined a lint](define_lints.md), written [UI tests](write_tests.md) Once we have [defined a lint](define_lints.md), written [UI
and chosen [the lint pass](lint_passes.md) for the lint, we can begin the tests](write_tests.md) and chosen [the lint pass](lint_passes.md) for the lint,
implementation of the lint logic so that we can emit it and gradually work we can begin the implementation of the lint logic so that we can emit it and
towards a lint that behaves as expected. gradually work towards a lint that behaves as expected.
Note that we will not go into concrete implementation of a lint logic in this Note that we will not go into concrete implementation of a lint logic in this
chapter. We will go into details in later chapters as well as in two examples chapter. We will go into details in later chapters as well as in two examples of
of real Clippy lints. real Clippy lints.
To emit a lint, we must implement a pass (see [Lint Passes](lint_passes.md)) for the lint that we have To emit a lint, we must implement a pass (see [Lint Passes](lint_passes.md)) for
declared. In this example we'll implement a "late" lint, so take a look at the [LateLintPass][late_lint_pass] the lint that we have declared. In this example we'll implement a "late" lint,
documentation, which provides an abundance of methods that we can implement for our lint. so take a look at the [LateLintPass][late_lint_pass] documentation, which
provides an abundance of methods that we can implement for our lint.
```rust ```rust
pub trait LateLintPass<'tcx>: LintPass { pub trait LateLintPass<'tcx>: LintPass {
@ -19,31 +20,32 @@ pub trait LateLintPass<'tcx>: LintPass {
} }
``` ```
By far the most common method used for Clippy lints is [`check_expr` method][late_check_expr], By far the most common method used for Clippy lints is [`check_expr`
this is because Rust is an expression language and, more often than not, method][late_check_expr], this is because Rust is an expression language and,
the lint we want to work on must examine expressions. more often than not, the lint we want to work on must examine expressions.
> _Note:_ If you don't fully understand what expressions are in Rust, > _Note:_ If you don't fully understand what expressions are in Rust, take a
> take a look at the official documentation on [expressions][rust_expressions] > look at the official documentation on [expressions][rust_expressions]
Other common ones include the [`check_fn` method][late_check_fn] and the Other common ones include the [`check_fn` method][late_check_fn] and the
[`check_item` method][late_check_item]. [`check_item` method][late_check_item].
### Emitting a lint ### Emitting a lint
Inside the trait method that we implement, we can write down the lint logic Inside the trait method that we implement, we can write down the lint logic and
and emit the lint with suggestions. emit the lint with suggestions.
Clippy's [diagnostics] provides quite a few diagnostic functions that we can Clippy's [diagnostics] provides quite a few diagnostic functions that we can use
use to emit lints. Take a look at the documentation to pick one that suits to emit lints. Take a look at the documentation to pick one that suits your
your lint's needs the best. Some common ones you will encounter in the Clippy lint's needs the best. Some common ones you will encounter in the Clippy
repository includes: repository includes:
- [`span_lint`]: Emits a lint without providing any other information - [`span_lint`]: Emits a lint without providing any other information
- [`span_lint_and_note`]: Emits a lint and adds a note - [`span_lint_and_note`]: Emits a lint and adds a note
- [`span_lint_and_help`]: Emits a lint and provides a helpful message - [`span_lint_and_help`]: Emits a lint and provides a helpful message
- [`span_lint_and_sugg`]: Emits a lint and provides a suggestion to fix the code - [`span_lint_and_sugg`]: Emits a lint and provides a suggestion to fix the code
- [`span_lint_and_then`]: Like `span_lint`, but allows for a lot of output customization. - [`span_lint_and_then`]: Like `span_lint`, but allows for a lot of output
customization.
```rust ```rust
impl<'tcx> LateLintPass<'tcx> for LintName { impl<'tcx> LateLintPass<'tcx> for LintName {
@ -63,16 +65,17 @@ impl<'tcx> LateLintPass<'tcx> for LintName {
} }
``` ```
> Note: The message should be matter of fact and avoid > Note: The message should be matter of fact and avoid capitalization and
> capitalization and punctuation. If multiple sentences are needed, the messages should probably be split up into an > punctuation. If multiple sentences are needed, the messages should probably be
> error + a help / note / suggestion message. > split up into an error + a help / note / suggestion message.
## Suggestions: Automatic fixes ## Suggestions: Automatic fixes
Some lints know what to change in order to fix the code. For example, the lint Some lints know what to change in order to fix the code. For example, the lint
[`range_plus`][range_plus_one] warns for ranges where the user wrote `x..y + 1` instead of using an [`range_plus_one`][range_plus_one] warns for ranges where the user wrote `x..y +
[inclusive range][inclusive_range] (`x..=1`). The fix to this code would be changing the `x..y + 1` expression 1` instead of using an [inclusive range][inclusive_range] (`x..=y`). The fix to
to `x..=y`. **This is where suggestions come in**. this code would be changing the `x..y + 1` expression to `x..=y`. **This is
where suggestions come in**.
A suggestion is a change that the lint provides to fix the issue it is linting. A suggestion is a change that the lint provides to fix the issue it is linting.
The output looks something like this (from the example earlier): The output looks something like this (from the example earlier):
@ -85,16 +88,17 @@ LL | for _ in 1..1 + 1 {}
| ^^^^^^^^ help: use: `1..=1` | ^^^^^^^^ help: use: `1..=1`
``` ```
**Not all suggestions are always right**, some of them require human supervision, that's why we have **Not all suggestions are always right**, some of them require human
[Applicability][applicability]. supervision, that's why we have [Applicability][applicability].
Applicability indicates confidence in the correctness of the suggestion, some are always right Applicability indicates confidence in the correctness of the suggestion, some
(`Applicability::MachineApplicable`), but we use `Applicability::MaybeIncorrect` and others when talking about a lint are always right (`Applicability::MachineApplicable`), but we use
that may be incorrect. `Applicability::MaybeIncorrect` and others when talking about a suggestion that
may be incorrect.
--- ### Example
The same lint `LINT_NAME` but that emits a suggestion would be something like this: The same lint `LINT_NAME` but that emits a suggestion would look something like this:
```rust ```rust
impl<'tcx> LateLintPass<'tcx> for LintName { impl<'tcx> LateLintPass<'tcx> for LintName {
@ -107,22 +111,27 @@ impl<'tcx> LateLintPass<'tcx> for LintName {
span, span,
"message on why the lint is emitted", "message on why the lint is emitted",
"use", "use",
"suggestion (don't forget to integrate things from the source, like variable names)", // < Suggestion format!("foo + {} * bar", snippet(cx, expr.span, "<default>")), // < Suggestion
Applicability::MachineApplicable Applicability::MachineApplicable,
); );
} }
} }
} }
``` ```
Suggestions generally use the [`format!`](format_macro) macro to interpolate the old values with the new ones. Suggestions generally use the [`format!`](format_macro) macro to interpolate the
old values with the new ones. To get code snippets, use one of the `snippet*`
functions from `clippy_utils::source`.
## How to choose between notes, help messages and suggestions ## How to choose between notes, help messages and suggestions
Notes are presented separately from the main lint message, they provide useful information that the user needs to Notes are presented separately from the main lint message, they provide useful
understand why the lint was activated. They are the most helpful when attached to a span. information that the user needs to understand why the lint was activated. They
are the most helpful when attached to a span.
Example: Examples:
### Notes
```text ```text
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
@ -139,10 +148,11 @@ note: argument has type &SomeStruct
| ^^^^^^^^^^^ | ^^^^^^^^^^^
``` ```
--- ### Help Messages
Help messages are specifically to help the user. These are used in situation where you can't provide a specific Help messages are specifically to help the user. These are used in situation
machine applicable suggestion. They can also be attached to a span. where you can't provide a specific machine applicable suggestion. They can also
be attached to a span.
Example: Example:
@ -156,10 +166,11 @@ error: constant division of 0.0 with 0.0 will always result in NaN
= help: consider using `f64::NAN` if you would like a constant representing NaN = help: consider using `f64::NAN` if you would like a constant representing NaN
``` ```
--- ### Suggestions
Suggestions are the most helpful, they are changes to the source code to fix the error. The magic Suggestions are the most helpful, they are changes to the source code to fix the
in suggestions is that tools like `rustfix` can detect them and automatically fix your code. error. The magic in suggestions is that tools like `rustfix` can detect them and
automatically fix your code.
Example: Example:
@ -170,21 +181,20 @@ error: This `.fold` can be more succinctly expressed as `.any`
390 | let _ = (0..3).fold(false, |acc, x| acc || x > 2); 390 | let _ = (0..3).fold(false, |acc, x| acc || x > 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
| |
= note: `-D fold-any` implied by `-D warnings`
``` ```
### Snippets ### Snippets
Snippets are pieces of the source code (as a string), they are extracted generally using the [`snippet`][snippet_fn] Snippets are pieces of the source code (as a string), they are extracted
function. generally using the [`snippet`][snippet_fn] function.
For example, if you want to know how an item looks (and you know the item's span), you could use For example, if you want to know how an item looks (and you know the item's
`snippet(cx, span, "..")`. span), you could use `snippet(cx, span, "..")`.
## Final: Run UI Tests to Emit the Lint ## Final: Run UI Tests to Emit the Lint
Now, if we run our [UI test](write_tests.md), we should see that the compiler now Now, if we run our [UI test](write_tests.md), we should see that Clippy now
produce output that contains the lint message we designed. produces output that contains the lint message we designed.
The next step is to implement the logic properly, which is a detail that we will The next step is to implement the logic properly, which is a detail that we will
cover in the next chapters. cover in the next chapters.