@@ -11,21 +11,24 @@ because that's clearly a non-descriptive name.
1111 - [ Setup] ( #setup )
1212 - [ Getting Started] ( #getting-started )
1313 - [ Testing] ( #testing )
14+ - [ Cargo lints] ( #cargo-lints )
1415 - [ Rustfix tests] ( #rustfix-tests )
1516 - [ Edition 2018 tests] ( #edition-2018-tests )
1617 - [ Testing manually] ( #testing-manually )
1718 - [ Lint declaration] ( #lint-declaration )
19+ - [ Lint registration] ( #lint-registration )
1820 - [ Lint passes] ( #lint-passes )
1921 - [ Emitting a lint] ( #emitting-a-lint )
2022 - [ Adding the lint logic] ( #adding-the-lint-logic )
2123 - [ Specifying the lint's minimum supported Rust version (MSRV)] ( #specifying-the-lints-minimum-supported-rust-version-msrv )
2224 - [ Author lint] ( #author-lint )
25+ - [ Print HIR lint] ( #print-hir-lint )
2326 - [ Documentation] ( #documentation )
2427 - [ Running rustfmt] ( #running-rustfmt )
2528 - [ Debugging] ( #debugging )
2629 - [ PR Checklist] ( #pr-checklist )
2730 - [ Adding configuration to a lint] ( #adding-configuration-to-a-lint )
28- - [ Cheatsheet ] ( #cheatsheet )
31+ - [ Cheat Sheet ] ( #cheat-sheet )
2932
3033## Setup
3134
@@ -42,9 +45,9 @@ take a look at our [lint naming guidelines][lint_naming]. To get started on this
4245lint you can run `cargo dev new_lint --name=foo_functions --pass=early
4346--category=pedantic` (category will default to nursery if not provided). This
4447command will create two files: ` tests/ui/foo_functions.rs ` and
45- ` clippy_lints/src/foo_functions.rs ` , as well as run ` cargo dev update_lints ` to
46- register the new lint. For cargo lints, two project hierarchies (fail/pass) will
47- be created by default under ` tests/ui-cargo ` .
48+ ` clippy_lints/src/foo_functions.rs ` , as well as
49+ [ registering the lint] ( #lint-registration ) . For cargo lints, two project
50+ hierarchies (fail/pass) will be created by default under ` tests/ui-cargo ` .
4851
4952Next, we'll open up these files and add our lint!
5053
@@ -155,7 +158,7 @@ Manually testing against an example file can be useful if you have added some
155158your local modifications, run
156159
157160```
158- env __CLIPPY_INTERNAL_TESTS=true cargo run --bin clippy-driver -- -L ./target/debug input.rs
161+ cargo dev lint input.rs
159162```
160163
161164from the working copy root. With tests in place, let's have a look at
@@ -179,17 +182,15 @@ the auto-generated lint declaration to have a real description, something like t
179182
180183``` rust
181184declare_clippy_lint! {
182- /// ** What it does:**
185+ /// ### What it does
183186 ///
184- /// **Why is this bad?**
185- ///
186- /// **Known problems:** None.
187- ///
188- /// **Example:**
187+ /// ### Why is this bad?
189188 ///
189+ /// ### Example
190190 /// ```rust
191191 /// // example code
192192 /// ```
193+ #[clippy:: version = " 1.29.0" ]
193194 pub FOO_FUNCTIONS ,
194195 pedantic ,
195196 " function named `foo`, which is not a descriptive name"
@@ -200,6 +201,10 @@ declare_clippy_lint! {
200201 section. This is the default documentation style and will be displayed
201202 [ like this] [ example_lint_page ] . To render and open this documentation locally
202203 in a browser, run ` cargo dev serve ` .
204+ * The ` #[clippy::version] ` attribute will be rendered as part of the lint documentation.
205+ The value should be set to the current Rust version that the lint is developed in,
206+ it can be retrieved by running ` rustc -vV ` in the rust-clippy directory. The version
207+ is listed under * release* . (Use the version without the ` -nightly ` ) suffix.
203208* ` FOO_FUNCTIONS ` is the name of our lint. Be sure to follow the
204209 [ lint naming guidelines] [ lint_naming ] here when naming your lint.
205210 In short, the name should state the thing that is being checked for and
@@ -222,32 +227,34 @@ declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]);
222227impl EarlyLintPass for FooFunctions {}
223228```
224229
225- Normally after declaring the lint, we have to run ` cargo dev update_lints ` ,
226- which updates some files, so Clippy knows about the new lint. Since we used
227- ` cargo dev new_lint ... ` to generate the lint declaration, this was done
228- automatically. While ` update_lints ` automates most of the things, it doesn't
229- automate everything. We will have to register our lint pass manually in the
230- ` register_plugins ` function in ` clippy_lints/src/lib.rs ` :
230+ [ declare_clippy_lint ] : https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
231+ [ example_lint_page ] : https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
232+ [ lint_naming ] : https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
233+ [ category_level_mapping ] : https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
234+
235+ ## Lint registration
236+
237+ When using ` cargo dev new_lint ` , the lint is automatically registered and
238+ nothing more has to be done.
239+
240+ When declaring a new lint by hand and ` cargo dev update_lints ` is used, the lint
241+ pass may have to be registered manually in the ` register_plugins ` function in
242+ ` clippy_lints/src/lib.rs ` :
231243
232244``` rust
233- store . register_early_pass (|| box foo_functions :: FooFunctions );
245+ store . register_early_pass (|| Box :: new ( foo_functions :: FooFunctions ) );
234246```
235247
236248As one may expect, there is a corresponding ` register_late_pass ` method
237249available as well. Without a call to one of ` register_early_pass ` or
238250` register_late_pass ` , the lint pass in question will not be run.
239251
240- One reason that ` cargo dev ` does not automate this step is that multiple lints
241- can use the same lint pass, so registering the lint pass may already be done
242- when adding a new lint. Another reason that this step is not automated is that
243- the order that the passes are registered determines the order the passes
244- actually run, which in turn affects the order that any emitted lints are output
245- in.
246-
247- [ declare_clippy_lint ] : https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
248- [ example_lint_page ] : https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
249- [ lint_naming ] : https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
250- [ category_level_mapping ] : https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
252+ One reason that ` cargo dev update_lints ` does not automate this step is that
253+ multiple lints can use the same lint pass, so registering the lint pass may
254+ already be done when adding a new lint. Another reason that this step is not
255+ automated is that the order that the passes are registered determines the order
256+ the passes actually run, which in turn affects the order that any emitted lints
257+ are output in.
251258
252259## Lint passes
253260
@@ -425,7 +432,7 @@ The project's MSRV can then be matched against the feature MSRV in the LintPass
425432using the ` meets_msrv ` utility function.
426433
427434``` rust
428- if ! meets_msrv (self . msrv. as_ref (), & msrvs :: STR_STRIP_PREFIX ) {
435+ if ! meets_msrv (self . msrv, msrvs :: STR_STRIP_PREFIX ) {
429436 return ;
430437}
431438```
@@ -478,6 +485,19 @@ you are implementing your lint.
478485
479486[ author_example ] : https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55
480487
488+ ## Print HIR lint
489+
490+ To implement a lint, it's helpful to first understand the internal representation
491+ that rustc uses. Clippy has the ` #[clippy::dump] ` attribute that prints the
492+ [ _ High-Level Intermediate Representation (HIR)_ ] of the item, statement, or
493+ expression that the attribute is attached to. To attach the attribute to expressions
494+ you often need to enable ` #![feature(stmt_expr_attributes)] ` .
495+
496+ [ Here] [ print_hir_example ] you can find an example, just select _ Tools_ and run _ Clippy_ .
497+
498+ [ _High-Level Intermediate Representation (HIR)_ ] : https://rustc-dev-guide.rust-lang.org/hir.html
499+ [ print_hir_example ] : https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=daf14db3a7f39ca467cd1b86c34b9afb
500+
481501## Documentation
482502
483503The final thing before submitting our PR is to add some documentation to our
@@ -487,21 +507,23 @@ Please document your lint with a doc comment akin to the following:
487507
488508``` rust
489509declare_clippy_lint! {
490- /// **What it does:** Checks for ... (describe what the lint matches).
510+ /// ### What it does
511+ /// Checks for ... (describe what the lint matches).
491512 ///
492- /// **Why is this bad?** Supply the reason for linting the code.
513+ /// ### Why is this bad?
514+ /// Supply the reason for linting the code.
493515 ///
494- /// **Known problems:** None. (Or describe where it could go wrong.)
495- ///
496- /// **Example:**
516+ /// ### Example
497517 ///
498518 /// ```rust,ignore
499- /// // Bad
500- /// Insert a short example of code that triggers the lint
501- ///
502- /// // Good
503- /// Insert a short example of improved code that doesn't trigger the lint
519+ /// // A short example of code that triggers the lint
504520 /// ```
521+ ///
522+ /// Use instead:
523+ /// ```rust,ignore
524+ /// // A short example of improved code that doesn't trigger the lint
525+ /// ```
526+ #[clippy:: version = " 1.29.0" ]
505527 pub FOO_FUNCTIONS ,
506528 pedantic ,
507529 " function named `foo`, which is not a descriptive name"
@@ -558,14 +580,16 @@ directory. Adding a configuration to a lint can be useful for thresholds or to c
558580behavior that can be seen as a false positive for some users. Adding a configuration is done
559581in the following steps:
560582
561- 1 . Adding a new configuration entry to [ clippy_utils:: conf] ( /clippy_utils /src/conf.rs )
583+ 1 . Adding a new configuration entry to [ clippy_lints::utils:: conf] ( /clippy_lints /src/utils /conf.rs )
562584 like this:
563585 ``` rust
564- /// Lint: LINT_NAME. <The configuration field doc comment>
586+ /// Lint: LINT_NAME.
587+ ///
588+ /// <The configuration field doc comment>
565589 (configuration_ident : Type = DefaultValue ),
566590 ```
567- The configuration value and identifier should usually be the same . The doc comment will be
568- automatically added to the lint documentation .
591+ The doc comment is automatically added to the documentation of the listed lints . The default
592+ value will be formatted using the ` Debug ` implementation of the type .
5695932 . Adding the configuration value to the lint impl struct :
570594 1 . This first requires the definition of a lint impl struct . Lint impl structs are usually
571595 generated with the `declare_lint_pass! ` macro . This struct needs to be defined manually
@@ -626,14 +650,14 @@ in the following steps:
626650 with the configuration value and a rust file that should be linted by Clippy . The test can
627651 otherwise be written as usual .
628652
629- ## Cheatsheet
653+ ## Cheat Sheet
630654
631655Here are some pointers to things you are likely going to need for every lint :
632656
633657* [Clippy utils ][utils ] - Various helper functions . Maybe the function you need
634- is already in here (` implements_trait `, ` match_def_path `, `snippet `, etc )
658+ is already in here ([` is_type_diagnostic_item `], [` implements_trait `], [ `snippet `] , etc )
635659* [Clippy diagnostics ][diagnostics ]
636- * [The ` if_chain ` macro ][ if_chain ]
660+ * [Let chains ][ let - chains ]
637661* [`from_expansion `][from_expansion ] and [`in_external_macro `][in_external_macro ]
638662* [`Span `][span ]
639663* [`Applicability `][applicability ]
@@ -657,8 +681,11 @@ documentation currently. This is unfortunate, but in most cases you can probably
657681get away with copying things from existing similar lints . If you are stuck ,
658682don 't hesitate to ask on [Zulip ] or in the issue / PR .
659683
660- [utils ]: https : // github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/lib.rs
661- [if_chain ]: https : // docs.rs/if_chain/*/if_chain/
684+ [utils ]: https : // doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/index.html
685+ [`is_type_diagnostic_item `]: https : // doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.is_type_diagnostic_item.html
686+ [`implements_trait `]: https : // doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.implements_trait.html
687+ [`snippet `]: https : // doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html
688+ [let - chains ]: https : // github.com/rust-lang/rust/pull/94927
662689[from_expansion ]: https : // doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
663690[in_external_macro ]: https : // doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
664691[span ]: https : // doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
0 commit comments