Formatting and minor wording fixes
This commit is contained in:
parent
f76615a7ac
commit
9b8b83556b
@ -1,17 +1,18 @@
|
||||
# Emitting a lint
|
||||
|
||||
Once we have [defined a lint](define_lints.md), written [UI tests](write_tests.md)
|
||||
and chosen [the lint pass](lint_passes.md) for the lint, we can begin the
|
||||
implementation of the lint logic so that we can emit it and gradually work
|
||||
towards a lint that behaves as expected.
|
||||
Once we have [defined a lint](define_lints.md), written [UI
|
||||
tests](write_tests.md) and chosen [the lint pass](lint_passes.md) for the lint,
|
||||
we can begin the implementation of the lint logic so that we can emit it and
|
||||
gradually work towards a lint that behaves as expected.
|
||||
|
||||
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
|
||||
of real Clippy lints.
|
||||
chapter. We will go into details in later chapters as well as in two examples of
|
||||
real Clippy lints.
|
||||
|
||||
To emit a lint, we must implement a pass (see [Lint Passes](lint_passes.md)) for the lint that we have
|
||||
declared. In this example we'll implement a "late" 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.
|
||||
To emit a lint, we must implement a pass (see [Lint Passes](lint_passes.md)) for
|
||||
the lint that we have declared. In this example we'll implement a "late" 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
|
||||
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],
|
||||
this is because Rust is an expression language and, more often than not,
|
||||
the lint we want to work on must examine expressions.
|
||||
By far the most common method used for Clippy lints is [`check_expr`
|
||||
method][late_check_expr], this is because Rust is an expression language and,
|
||||
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,
|
||||
> take a look at the official documentation on [expressions][rust_expressions]
|
||||
> _Note:_ If you don't fully understand what expressions are in Rust, take a
|
||||
> look at the official documentation on [expressions][rust_expressions]
|
||||
|
||||
Other common ones include the [`check_fn` method][late_check_fn] and the
|
||||
[`check_item` method][late_check_item].
|
||||
|
||||
### Emitting a lint
|
||||
|
||||
Inside the trait method that we implement, we can write down the lint logic
|
||||
and emit the lint with suggestions.
|
||||
Inside the trait method that we implement, we can write down the lint logic and
|
||||
emit the lint with suggestions.
|
||||
|
||||
Clippy's [diagnostics] provides quite a few diagnostic functions that we can
|
||||
use to emit lints. Take a look at the documentation to pick one that suits
|
||||
your lint's needs the best. Some common ones you will encounter in the Clippy
|
||||
Clippy's [diagnostics] provides quite a few diagnostic functions that we can use
|
||||
to emit lints. Take a look at the documentation to pick one that suits your
|
||||
lint's needs the best. Some common ones you will encounter in the Clippy
|
||||
repository includes:
|
||||
|
||||
- [`span_lint`]: Emits a lint without providing any other information
|
||||
- [`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_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
|
||||
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
|
||||
> capitalization and punctuation. If multiple sentences are needed, the messages should probably be split up into an
|
||||
> error + a help / note / suggestion message.
|
||||
> Note: The message should be matter of fact and avoid capitalization and
|
||||
> punctuation. If multiple sentences are needed, the messages should probably be
|
||||
> split up into an error + a help / note / suggestion message.
|
||||
|
||||
## Suggestions: Automatic fixes
|
||||
|
||||
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
|
||||
[inclusive range][inclusive_range] (`x..=1`). The fix to this code would be changing the `x..y + 1` expression
|
||||
to `x..=y`. **This is where suggestions come in**.
|
||||
[`range_plus_one`][range_plus_one] warns for ranges where the user wrote `x..y +
|
||||
1` instead of using an [inclusive range][inclusive_range] (`x..=y`). The fix to
|
||||
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.
|
||||
The output looks something like this (from the example earlier):
|
||||
@ -85,16 +88,17 @@ LL | for _ in 1..1 + 1 {}
|
||||
| ^^^^^^^^ help: use: `1..=1`
|
||||
```
|
||||
|
||||
**Not all suggestions are always right**, some of them require human supervision, that's why we have
|
||||
[Applicability][applicability].
|
||||
**Not all suggestions are always right**, some of them require human
|
||||
supervision, that's why we have [Applicability][applicability].
|
||||
|
||||
Applicability indicates confidence in the correctness of the suggestion, some are always right
|
||||
(`Applicability::MachineApplicable`), but we use `Applicability::MaybeIncorrect` and others when talking about a lint
|
||||
that may be incorrect.
|
||||
Applicability indicates confidence in the correctness of the suggestion, some
|
||||
are always right (`Applicability::MachineApplicable`), but we use
|
||||
`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
|
||||
impl<'tcx> LateLintPass<'tcx> for LintName {
|
||||
@ -107,22 +111,27 @@ impl<'tcx> LateLintPass<'tcx> for LintName {
|
||||
span,
|
||||
"message on why the lint is emitted",
|
||||
"use",
|
||||
"suggestion (don't forget to integrate things from the source, like variable names)", // < Suggestion
|
||||
Applicability::MachineApplicable
|
||||
format!("foo + {} * bar", snippet(cx, expr.span, "<default>")), // < Suggestion
|
||||
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
|
||||
|
||||
Notes are presented separately from the main lint message, they provide useful information that the user needs to
|
||||
understand why the lint was activated. They are the most helpful when attached to a span.
|
||||
Notes are presented separately from the main lint message, they provide useful
|
||||
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
|
||||
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
|
||||
machine applicable suggestion. They can also be attached to a span.
|
||||
Help messages are specifically to help the user. These are used in situation
|
||||
where you can't provide a specific machine applicable suggestion. They can also
|
||||
be attached to a span.
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
---
|
||||
### Suggestions
|
||||
|
||||
Suggestions are the most helpful, they are changes to the source code to fix the error. The magic
|
||||
in suggestions is that tools like `rustfix` can detect them and automatically fix your code.
|
||||
Suggestions are the most helpful, they are changes to the source code to fix the
|
||||
error. The magic in suggestions is that tools like `rustfix` can detect them and
|
||||
automatically fix your code.
|
||||
|
||||
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);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
|
||||
|
|
||||
= note: `-D fold-any` implied by `-D warnings`
|
||||
```
|
||||
|
||||
### Snippets
|
||||
|
||||
Snippets are pieces of the source code (as a string), they are extracted generally using the [`snippet`][snippet_fn]
|
||||
function.
|
||||
Snippets are pieces of the source code (as a string), they are extracted
|
||||
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
|
||||
`snippet(cx, span, "..")`.
|
||||
For example, if you want to know how an item looks (and you know the item's
|
||||
span), you could use `snippet(cx, span, "..")`.
|
||||
|
||||
## 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
|
||||
produce output that contains the lint message we designed.
|
||||
Now, if we run our [UI test](write_tests.md), we should see that Clippy now
|
||||
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
|
||||
cover in the next chapters.
|
||||
|
Loading…
Reference in New Issue
Block a user