1
1
# Emitting a lint
2
2
3
- Once we have [ defined a lint] ( define_lints.md ) , written [ UI tests ] ( write_tests.md )
4
- and chosen [ the lint pass] ( lint_passes.md ) for the lint, we can begin the
5
- implementation of the lint logic so that we can emit it and gradually work
6
- towards a lint that behaves as expected.
3
+ Once we have [ defined a lint] ( define_lints.md ) , written [ UI
4
+ tests ] ( write_tests.md ) and chosen [ the lint pass] ( lint_passes.md ) for the lint,
5
+ we can begin the implementation of the lint logic so that we can emit it and
6
+ gradually work towards a lint that behaves as expected.
7
7
8
8
Note that we will not go into concrete implementation of a lint logic in this
9
- chapter. We will go into details in later chapters as well as in two examples
10
- of real Clippy lints.
9
+ chapter. We will go into details in later chapters as well as in two examples of
10
+ real Clippy lints.
11
11
12
- To emit a lint, we must implement a pass (see [ Lint Passes] ( lint_passes.md ) ) for the lint that we have
13
- declared. In this example we'll implement a "late" lint, so take a look at the [ LateLintPass] [ late_lint_pass ]
14
- documentation, which provides an abundance of methods that we can implement for our lint.
12
+ To emit a lint, we must implement a pass (see [ Lint Passes] ( lint_passes.md ) ) for
13
+ the lint that we have declared. In this example we'll implement a "late" lint,
14
+ so take a look at the [ LateLintPass] [ late_lint_pass ] documentation, which
15
+ provides an abundance of methods that we can implement for our lint.
15
16
16
17
``` rust
17
18
pub trait LateLintPass <'tcx >: LintPass {
18
19
// Trait methods
19
20
}
20
21
```
21
22
22
- By far the most common method used for Clippy lints is [ ` check_expr ` method ] [ late_check_expr ] ,
23
- this is because Rust is an expression language and, more often than not ,
24
- the lint we want to work on must examine expressions.
23
+ By far the most common method used for Clippy lints is [ ` check_expr `
24
+ method ] [ late_check_expr ] , this is because Rust is an expression language and,
25
+ more often than not, the lint we want to work on must examine expressions.
25
26
26
- > _ Note:_ If you don't fully understand what expressions are in Rust,
27
- > take a look at the official documentation on [ expressions] [ rust_expressions ]
27
+ > _ Note:_ If you don't fully understand what expressions are in Rust, take a
28
+ > look at the official documentation on [ expressions] [ rust_expressions ]
28
29
29
30
Other common ones include the [ ` check_fn ` method] [ late_check_fn ] and the
30
31
[ ` check_item ` method] [ late_check_item ] .
31
32
32
33
### Emitting a lint
33
34
34
- Inside the trait method that we implement, we can write down the lint logic
35
- and emit the lint with suggestions.
35
+ Inside the trait method that we implement, we can write down the lint logic and
36
+ emit the lint with suggestions.
36
37
37
- Clippy's [ diagnostics] provides quite a few diagnostic functions that we can
38
- use to emit lints. Take a look at the documentation to pick one that suits
39
- your lint's needs the best. Some common ones you will encounter in the Clippy
38
+ Clippy's [ diagnostics] provides quite a few diagnostic functions that we can use
39
+ to emit lints. Take a look at the documentation to pick one that suits your
40
+ lint's needs the best. Some common ones you will encounter in the Clippy
40
41
repository includes:
41
42
42
43
- [ ` span_lint ` ] : Emits a lint without providing any other information
43
44
- [ ` span_lint_and_note ` ] : Emits a lint and adds a note
44
45
- [ ` span_lint_and_help ` ] : Emits a lint and provides a helpful message
45
46
- [ ` span_lint_and_sugg ` ] : Emits a lint and provides a suggestion to fix the code
46
- - [ ` span_lint_and_then ` ] : Like ` span_lint ` , but allows for a lot of output customization.
47
+ - [ ` span_lint_and_then ` ] : Like ` span_lint ` , but allows for a lot of output
48
+ customization.
47
49
48
50
``` rust
49
51
impl <'tcx > LateLintPass <'tcx > for LintName {
@@ -63,16 +65,17 @@ impl<'tcx> LateLintPass<'tcx> for LintName {
63
65
}
64
66
```
65
67
66
- > Note: The message should be matter of fact and avoid
67
- > capitalization and punctuation. If multiple sentences are needed, the messages should probably be split up into an
68
- > error + a help / note / suggestion message.
68
+ > Note: The message should be matter of fact and avoid capitalization and
69
+ > punctuation. If multiple sentences are needed, the messages should probably be
70
+ > split up into an error + a help / note / suggestion message.
69
71
70
72
## Suggestions: Automatic fixes
71
73
72
74
Some lints know what to change in order to fix the code. For example, the lint
73
- [ ` range_plus ` ] [ range_plus_one ] warns for ranges where the user wrote ` x..y + 1 ` instead of using an
74
- [ inclusive range] [ inclusive_range ] (` x..=1 ` ). The fix to this code would be changing the ` x..y + 1 ` expression
75
- to ` x..=y ` . ** This is where suggestions come in** .
75
+ [ ` range_plus_one ` ] [ range_plus_one ] warns for ranges where the user wrote `x..y +
76
+ 1` instead of using an [inclusive range][inclusive_range] ( ` x..=y`). The fix to
77
+ this code would be changing the ` x..y + 1 ` expression to ` x..=y ` . ** This is
78
+ where suggestions come in** .
76
79
77
80
A suggestion is a change that the lint provides to fix the issue it is linting.
78
81
The output looks something like this (from the example earlier):
@@ -85,16 +88,17 @@ LL | for _ in 1..1 + 1 {}
85
88
| ^^^^^^^^ help: use: `1..=1`
86
89
```
87
90
88
- ** Not all suggestions are always right** , some of them require human supervision, that's why we have
89
- [ Applicability] [ applicability ] .
91
+ ** Not all suggestions are always right** , some of them require human
92
+ supervision, that's why we have [ Applicability] [ applicability ] .
90
93
91
- Applicability indicates confidence in the correctness of the suggestion, some are always right
92
- (` Applicability::MachineApplicable ` ), but we use ` Applicability::MaybeIncorrect ` and others when talking about a lint
93
- that may be incorrect.
94
+ Applicability indicates confidence in the correctness of the suggestion, some
95
+ are always right (` Applicability::MachineApplicable ` ), but we use
96
+ ` Applicability::MaybeIncorrect ` and others when talking about a suggestion that
97
+ may be incorrect.
94
98
95
- ---
99
+ ### Example
96
100
97
- The same lint ` LINT_NAME ` but that emits a suggestion would be something like this:
101
+ The same lint ` LINT_NAME ` but that emits a suggestion would look something like this:
98
102
99
103
``` rust
100
104
impl <'tcx > LateLintPass <'tcx > for LintName {
@@ -107,22 +111,27 @@ impl<'tcx> LateLintPass<'tcx> for LintName {
107
111
span ,
108
112
" message on why the lint is emitted" ,
109
113
" use" ,
110
- " suggestion (don't forget to integrate things from the source, like variable names) " , // < Suggestion
111
- Applicability :: MachineApplicable
114
+ format! ( " foo + {} * bar " , snippet ( cx , expr . span, " <default> " )) , // < Suggestion
115
+ Applicability :: MachineApplicable ,
112
116
);
113
117
}
114
118
}
115
119
}
116
120
```
117
121
118
- Suggestions generally use the [ ` format! ` ] ( format_macro ) macro to interpolate the old values with the new ones.
122
+ Suggestions generally use the [ ` format! ` ] ( format_macro ) macro to interpolate the
123
+ old values with the new ones. To get code snippets, use one of the ` snippet* `
124
+ functions from ` clippy_utils::source ` .
119
125
120
126
## How to choose between notes, help messages and suggestions
121
127
122
- Notes are presented separately from the main lint message, they provide useful information that the user needs to
123
- understand why the lint was activated. They are the most helpful when attached to a span.
128
+ Notes are presented separately from the main lint message, they provide useful
129
+ information that the user needs to understand why the lint was activated. They
130
+ are the most helpful when attached to a span.
124
131
125
- Example:
132
+ Examples:
133
+
134
+ ### Notes
126
135
127
136
``` text
128
137
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
139
148
| ^^^^^^^^^^^
140
149
```
141
150
142
- ---
151
+ ### Help Messages
143
152
144
- Help messages are specifically to help the user. These are used in situation where you can't provide a specific
145
- machine applicable suggestion. They can also be attached to a span.
153
+ Help messages are specifically to help the user. These are used in situation
154
+ where you can't provide a specific machine applicable suggestion. They can also
155
+ be attached to a span.
146
156
147
157
Example:
148
158
@@ -156,10 +166,11 @@ error: constant division of 0.0 with 0.0 will always result in NaN
156
166
= help: consider using `f64::NAN` if you would like a constant representing NaN
157
167
```
158
168
159
- ---
169
+ ### Suggestions
160
170
161
- Suggestions are the most helpful, they are changes to the source code to fix the error. The magic
162
- in suggestions is that tools like ` rustfix ` can detect them and automatically fix your code.
171
+ Suggestions are the most helpful, they are changes to the source code to fix the
172
+ error. The magic in suggestions is that tools like ` rustfix ` can detect them and
173
+ automatically fix your code.
163
174
164
175
Example:
165
176
@@ -170,21 +181,20 @@ error: This `.fold` can be more succinctly expressed as `.any`
170
181
390 | let _ = (0..3).fold(false, |acc, x| acc || x > 2);
171
182
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
172
183
|
173
- = note: `-D fold-any` implied by `-D warnings`
174
184
```
175
185
176
186
### Snippets
177
187
178
- Snippets are pieces of the source code (as a string), they are extracted generally using the [ ` snippet ` ] [ snippet_fn ]
179
- function.
188
+ Snippets are pieces of the source code (as a string), they are extracted
189
+ generally using the [ ` snippet ` ] [ snippet_fn ] function.
180
190
181
- For example, if you want to know how an item looks (and you know the item's span), you could use
182
- ` snippet(cx, span, "..") ` .
191
+ For example, if you want to know how an item looks (and you know the item's
192
+ span), you could use ` snippet(cx, span, "..") ` .
183
193
184
194
## Final: Run UI Tests to Emit the Lint
185
195
186
- Now, if we run our [ UI test] ( write_tests.md ) , we should see that the compiler now
187
- produce output that contains the lint message we designed.
196
+ Now, if we run our [ UI test] ( write_tests.md ) , we should see that Clippy now
197
+ produces output that contains the lint message we designed.
188
198
189
199
The next step is to implement the logic properly, which is a detail that we will
190
200
cover in the next chapters.
0 commit comments