Auto merge of #5299 - JohnTitor:contrib, r=flip1995
Clean-up docs Fixes #5268 changelog: none
This commit is contained in:
commit
16b925b748
2 changed files with 152 additions and 145 deletions
151
CONTRIBUTING.md
151
CONTRIBUTING.md
|
@ -8,10 +8,9 @@ something. We appreciate any sort of contributions, and don't want a wall of rul
|
|||
|
||||
Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document
|
||||
explains how you can contribute and how to get started. If you have any questions about contributing or need help with
|
||||
anything, feel free to ask questions on issues or visit the `#clippy` IRC channel on `irc.mozilla.org` or meet us in
|
||||
`#clippy` on [Discord](https://discord.gg/rust-lang).
|
||||
anything, feel free to ask questions on issues or visit the `#clippy` on [Discord].
|
||||
|
||||
All contributors are expected to follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html).
|
||||
All contributors are expected to follow the [Rust Code of Conduct].
|
||||
|
||||
* [Getting started](#getting-started)
|
||||
* [Finding something to fix/improve](#finding-something-to-fiximprove)
|
||||
|
@ -22,6 +21,9 @@ All contributors are expected to follow the [Rust Code of Conduct](http://www.ru
|
|||
* [Bors and Homu](#bors-and-homu)
|
||||
* [Contributions](#contributions)
|
||||
|
||||
[Discord]: https://discord.gg/rust-lang
|
||||
[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
|
||||
|
||||
## Getting started
|
||||
|
||||
High level approach:
|
||||
|
@ -36,57 +38,61 @@ High level approach:
|
|||
|
||||
All issues on Clippy are mentored, if you want help with a bug just ask @Manishearth, @llogiq, @mcarton or @oli-obk.
|
||||
|
||||
Some issues are easier than others. The [`good first issue`](https://github.com/rust-lang/rust-clippy/labels/good%20first%20issue)
|
||||
label can be used to find the easy issues. If you want to work on an issue, please leave a comment
|
||||
so that we can assign it to you!
|
||||
Some issues are easier than others. The [`good first issue`] label can be used to find the easy issues.
|
||||
If you want to work on an issue, please leave a comment so that we can assign it to you!
|
||||
|
||||
There are also some abandoned PRs, marked with
|
||||
[`S-inactive-closed`](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed).
|
||||
There are also some abandoned PRs, marked with [`S-inactive-closed`].
|
||||
Pretty often these PRs are nearly completed and just need some extra steps
|
||||
(formatting, addressing review comments, ...) to be merged. If you want to
|
||||
complete such a PR, please leave a comment in the PR and open a new one based
|
||||
on it.
|
||||
|
||||
Issues marked [`T-AST`](https://github.com/rust-lang/rust-clippy/labels/T-AST) involve simple
|
||||
matching of the syntax tree structure, and are generally easier than
|
||||
[`T-middle`](https://github.com/rust-lang/rust-clippy/labels/T-middle) issues, which involve types
|
||||
Issues marked [`T-AST`] involve simple matching of the syntax tree structure,
|
||||
and are generally easier than [`T-middle`] issues, which involve types
|
||||
and resolved paths.
|
||||
|
||||
[`T-AST`](https://github.com/rust-lang/rust-clippy/labels/T-AST) issues will generally need you to match against a
|
||||
predefined syntax structure. To figure out how this syntax structure is encoded in the AST, it is recommended to run
|
||||
`rustc -Z ast-json` on an example of the structure and compare with the [nodes in the AST
|
||||
docs](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast). Usually the lint will end up to be a nested series of
|
||||
matches and ifs, [like
|
||||
so](https://github.com/rust-lang/rust-clippy/blob/de5ccdfab68a5e37689f3c950ed1532ba9d652a0/src/misc.rs#L34).
|
||||
[`T-AST`] issues will generally need you to match against a predefined syntax structure.
|
||||
To figure out how this syntax structure is encoded in the AST, it is recommended to run
|
||||
`rustc -Z ast-json` on an example of the structure and compare with the [nodes in the AST docs].
|
||||
Usually the lint will end up to be a nested series of matches and ifs, [like so].
|
||||
|
||||
[`E-medium`](https://github.com/rust-lang/rust-clippy/labels/E-medium) issues are generally
|
||||
pretty easy too, though it's recommended you work on an E-easy issue first. They are mostly classified
|
||||
as `E-medium`, since they might be somewhat involved code wise, but not difficult per-se.
|
||||
[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an E-easy issue first.
|
||||
They are mostly classified as [`E-medium`], since they might be somewhat involved code wise,
|
||||
but not difficult per-se.
|
||||
|
||||
[`T-middle`](https://github.com/rust-lang/rust-clippy/labels/T-middle) issues can
|
||||
be more involved and require verifying types. The
|
||||
[`ty`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty) module contains a
|
||||
[`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a
|
||||
lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
|
||||
an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful.
|
||||
|
||||
[`good first issue`]: https://github.com/rust-lang/rust-clippy/labels/good%20first%20issue
|
||||
[`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed
|
||||
[`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST
|
||||
[`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle
|
||||
[`E-medium`]: https://github.com/rust-lang/rust-clippy/labels/E-medium
|
||||
[`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty
|
||||
[nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/
|
||||
[like so]: https://github.com/rust-lang/rust-clippy/blob/de5ccdfab68a5e37689f3c950ed1532ba9d652a0/src/misc.rs#L34
|
||||
|
||||
## Writing code
|
||||
|
||||
Have a look at the [docs for writing lints](doc/adding_lints.md) for more details. [Llogiq's blog post on
|
||||
lints](https://llogiq.github.io/2015/06/04/workflows.html) is also a nice primer to lint-writing, though it does get
|
||||
into advanced stuff and may be a bit outdated.
|
||||
Have a look at the [docs for writing lints][adding_lints] for more details. [Llogiq's blog post on lints]
|
||||
is also a nice primer to lint-writing, though it does get into advanced stuff and may be a bit outdated.
|
||||
|
||||
If you want to add a new lint or change existing ones apart from bugfixing, it's
|
||||
also a good idea to give the [stability guarantees][rfc_stability] and
|
||||
[lint categories][rfc_lint_cats] sections of the [Clippy 1.0 RFC][clippy_rfc] a
|
||||
quick read.
|
||||
|
||||
[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
|
||||
[Llogiq's blog post on lints]: https://llogiq.github.io/2015/06/04/workflows.html
|
||||
[clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md
|
||||
[rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees
|
||||
[rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
|
||||
|
||||
## How Clippy works
|
||||
|
||||
Clippy is a [rustc compiler plugin][compiler_plugin]. The main entry point is at [`src/lib.rs`][main_entry]. In there,
|
||||
the lint registration is delegated to the [`clippy_lints`][lint_crate] crate.
|
||||
|
||||
[`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers them with the rustc
|
||||
plugin registry. For example, the [`else_if_without_else`][else_if_without_else] lint is registered like this:
|
||||
[`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers in the [`LintStore`].
|
||||
For example, the [`else_if_without_else`][else_if_without_else] lint is registered like this:
|
||||
|
||||
```rust
|
||||
// ./clippy_lints/src/lib.rs
|
||||
|
@ -95,25 +101,24 @@ plugin registry. For example, the [`else_if_without_else`][else_if_without_else]
|
|||
pub mod else_if_without_else;
|
||||
// ...
|
||||
|
||||
pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry) {
|
||||
pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
|
||||
// ...
|
||||
reg.register_early_lint_pass(box else_if_without_else::ElseIfWithoutElse);
|
||||
store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
|
||||
// ...
|
||||
|
||||
reg.register_lint_group("clippy::restriction", vec![
|
||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
||||
// ...
|
||||
else_if_without_else::ELSE_IF_WITHOUT_ELSE,
|
||||
LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
|
||||
// ...
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
The [`plugin::PluginRegistry`][plugin_registry] provides two methods to register lints:
|
||||
[register_early_lint_pass][reg_early_lint_pass] and [register_late_lint_pass][reg_late_lint_pass]. Both take an object
|
||||
The [`rustc_lint::LintStore`][`LintStore`] provides two methods to register lints:
|
||||
[register_early_pass][reg_early_pass] and [register_late_pass][reg_late_pass]. Both take an object
|
||||
that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in
|
||||
every single lint. It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `cargo dev
|
||||
update_lints` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to
|
||||
save you some time.
|
||||
update_lints`. When you are writing your own lint, you can use that script to save you some time.
|
||||
|
||||
```rust
|
||||
// ./clippy_lints/src/else_if_without_else.rs
|
||||
|
@ -135,8 +140,16 @@ The difference between `EarlyLintPass` and `LateLintPass` is that the methods of
|
|||
AST information. The methods of the `LateLintPass` trait are executed after type checking and contain type information
|
||||
via the `LateContext` parameter.
|
||||
|
||||
That's why the `else_if_without_else` example uses the `register_early_lint_pass` function. Because the [actual lint
|
||||
logic][else_if_without_else] does not depend on any type information.
|
||||
That's why the `else_if_without_else` example uses the `register_early_pass` function. Because the
|
||||
[actual lint logic][else_if_without_else] does not depend on any type information.
|
||||
|
||||
[lint_crate_entry]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
|
||||
[else_if_without_else]: https://github.com/rust-lang/rust-clippy/blob/4253aa7137cb7378acc96133c787e49a345c2b3c/clippy_lints/src/else_if_without_else.rs
|
||||
[`LintStore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html
|
||||
[reg_early_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_early_pass
|
||||
[reg_late_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_late_pass
|
||||
[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
|
||||
[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
|
||||
|
||||
## Fixing build failures caused by Rust
|
||||
|
||||
|
@ -145,8 +158,9 @@ the times we have to adapt to the changes and only very rarely there's an actual
|
|||
caused by Rust updates, can be a good way to learn about Rust internals.
|
||||
|
||||
In order to find out why Clippy does not work properly with a new Rust commit, you can use the [rust-toolstate commit
|
||||
history][toolstate_commit_history]. You will then have to look for the last commit that contains `test-pass ->
|
||||
build-fail` or `test-pass` -> `test-fail` for the `clippy-driver` component. [Here][toolstate_commit] is an example.
|
||||
history][toolstate_commit_history]. You will then have to look for the last commit that contains
|
||||
`test-pass -> build-fail` or `test-pass -> test-fail` for the `clippy-driver` component.
|
||||
[Here][toolstate_commit] is an example.
|
||||
|
||||
The commit message contains a link to the PR. The PRs are usually small enough to discover the breaking API change and
|
||||
if they are bigger, they likely include some discussion that may help you to fix Clippy.
|
||||
|
@ -158,14 +172,8 @@ If you decide to make Clippy work again with a Rust commit that breaks it,
|
|||
you probably want to install the latest Rust from master locally and run Clippy
|
||||
using that version of Rust.
|
||||
|
||||
You can use [rustup-toolchain-install-master][rtim] to do that:
|
||||
|
||||
```bash
|
||||
cargo install rustup-toolchain-install-master
|
||||
rustup-toolchain-install-master --force -n master -c rustc-dev
|
||||
rustup override set master
|
||||
cargo test
|
||||
```
|
||||
You can set up the master toolchain by running `./setup-toolchain.sh`. That script will install
|
||||
[rustup-toolchain-install-master][rtim] and master toolchain, then run `rustup override set master`.
|
||||
|
||||
After fixing the build failure on this repository, we can submit a pull request
|
||||
to [`rust-lang/rust`] to fix the toolstate.
|
||||
|
@ -182,6 +190,12 @@ git commit -m "Update Clippy"
|
|||
# Open a PR in rust-lang/rust
|
||||
```
|
||||
|
||||
[rustup_component_history]: https://rust-lang.github.io/rustup-components-history
|
||||
[toolstate_commit_history]: https://github.com/rust-lang-nursery/rust-toolstate/commits/master
|
||||
[toolstate_commit]: https://github.com/rust-lang-nursery/rust-toolstate/commit/aad74d8294e198a7cf8ac81a91aebb7f3bbcf727
|
||||
[rtim]: https://github.com/kennytm/rustup-toolchain-install-master
|
||||
[`rust-lang/rust`]: https://github.com/rust-lang/rust
|
||||
|
||||
## Issue and PR triage
|
||||
|
||||
Clippy is following the [Rust triage procedure][triage] for issues and pull
|
||||
|
@ -206,6 +220,12 @@ You can find the Clippy bors queue [here][homu_queue].
|
|||
If you have @bors permissions, you can find an overview of the available
|
||||
commands [here][homu_instructions].
|
||||
|
||||
[triage]: https://forge.rust-lang.org/triage-procedure.html
|
||||
[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash%20%3Aboom%3A
|
||||
[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug%20%3Abeetle%3A
|
||||
[homu]: https://github.com/rust-lang/homu
|
||||
[homu_instructions]: https://buildbot2.rust-lang.org/homu/
|
||||
[homu_queue]: https://buildbot2.rust-lang.org/homu/queue/clippy
|
||||
|
||||
## Contributions
|
||||
|
||||
|
@ -213,32 +233,9 @@ Contributions to Clippy should be made in the form of GitHub pull requests. Each
|
|||
be reviewed by a core contributor (someone with permission to land patches) and either landed in the
|
||||
main tree or given feedback for changes that would be required.
|
||||
|
||||
All code in this repository is under the [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0>)
|
||||
or the [MIT](http://opensource.org/licenses/MIT) license.
|
||||
All code in this repository is under the [Apache-2.0] or the [MIT] license.
|
||||
|
||||
<!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md -->
|
||||
|
||||
[main_entry]: https://github.com/rust-lang/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/src/lib.rs#L14
|
||||
[lint_crate]: https://github.com/rust-lang/rust-clippy/tree/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src
|
||||
[lint_crate_entry]: https://github.com/rust-lang/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src/lib.rs
|
||||
[else_if_without_else]: https://github.com/rust-lang/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src/else_if_without_else.rs
|
||||
[compiler_plugin]: https://doc.rust-lang.org/unstable-book/language-features/plugin.html#lint-plugins
|
||||
[plugin_registry]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin_impl/registry/struct.Registry.html
|
||||
[reg_early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin_impl/registry/struct.Registry.html#method.register_early_lint_pass
|
||||
[reg_late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin_impl/registry/struct.Registry.html#method.register_late_lint_pass
|
||||
[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.EarlyLintPass.html
|
||||
[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.LateLintPass.html
|
||||
[toolstate_commit_history]: https://github.com/rust-lang-nursery/rust-toolstate/commits/master
|
||||
[toolstate_commit]: https://github.com/rust-lang-nursery/rust-toolstate/commit/6ce0459f6bfa7c528ae1886492a3e0b5ef0ee547
|
||||
[rtim]: https://github.com/kennytm/rustup-toolchain-install-master
|
||||
[rustup_component_history]: https://mexus.github.io/rustup-components-history
|
||||
[clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md
|
||||
[rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees
|
||||
[rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
|
||||
[triage]: https://forge.rust-lang.org/triage-procedure.html
|
||||
[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash%20%3Aboom%3A
|
||||
[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug%20%3Abeetle%3A
|
||||
[homu]: https://github.com/servo/homu
|
||||
[homu_instructions]: https://buildbot2.rust-lang.org/homu/
|
||||
[homu_queue]: https://buildbot2.rust-lang.org/homu/queue/clippy
|
||||
[`rust-lang/rust`]: https://github.com/rust-lang/rust
|
||||
[Apache-2.0]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
[MIT]: https://opensource.org/licenses/MIT
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## Adding a new lint
|
||||
# Adding a new lint
|
||||
|
||||
You are probably here because you want to add a new lint to Clippy. If this is
|
||||
the first time you're contributing to Clippy, this document guides you through
|
||||
|
@ -25,14 +25,14 @@ because that's clearly a non-descriptive name.
|
|||
- [PR Checklist](#pr-checklist)
|
||||
- [Cheatsheet](#cheatsheet)
|
||||
|
||||
### Setup
|
||||
## Setup
|
||||
|
||||
When working on Clippy, you will need the current git master version of rustc,
|
||||
which can change rapidly. Make sure you're working near rust-clippy's master,
|
||||
and use the `setup-toolchain.sh` script to configure the appropriate toolchain
|
||||
for the Clippy directory.
|
||||
|
||||
### Getting Started
|
||||
## Getting Started
|
||||
|
||||
There is a bit of boilerplate code that needs to be set up when creating a new
|
||||
lint. Fortunately, you can use the clippy dev tools to handle this for you. We
|
||||
|
@ -45,7 +45,7 @@ two files: `tests/ui/foo_functions.rs` and `clippy_lints/src/foo_functions.rs`,
|
|||
as well as run `cargo dev update_lints` to register the new lint. Next, we'll
|
||||
open up these files and add our lint!
|
||||
|
||||
### Testing
|
||||
## Testing
|
||||
|
||||
Let's write some tests first that we can execute while we iterate on our lint.
|
||||
|
||||
|
@ -88,12 +88,10 @@ fn main() {
|
|||
let a = A;
|
||||
a.foo();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now we can run the test with `TESTNAME=foo_functions cargo uitest`.
|
||||
Currently this test will fail. If you go through the output you will see that we
|
||||
are told that `clippy::foo_functions` is an unknown lint, which is expected.
|
||||
Now we can run the test with `TESTNAME=foo_functions cargo uitest`,
|
||||
currently this test is meaningless though.
|
||||
|
||||
While we are working on implementing our lint, we can keep running the UI
|
||||
test. That allows us to check if the output is turning into what we want.
|
||||
|
@ -105,24 +103,26 @@ every time before running `tests/ui/update-all-references.sh`.
|
|||
Running `TESTNAME=foo_functions cargo uitest` should pass then. When we commit
|
||||
our lint, we need to commit the generated `.stderr` files, too.
|
||||
|
||||
### Rustfix tests
|
||||
## Rustfix tests
|
||||
|
||||
If the lint you are working on is making use of structured suggestions, the
|
||||
test file should include a `// run-rustfix` comment at the top. This will
|
||||
additionally run [rustfix](https://github.com/rust-lang-nursery/rustfix) for
|
||||
that test. Rustfix will apply the suggestions from the lint to the code of the
|
||||
test file and compare that to the contents of a `.fixed` file.
|
||||
additionally run [rustfix] for that test. Rustfix will apply the suggestions
|
||||
from the lint to the code of the test file and compare that to the contents of
|
||||
a `.fixed` file.
|
||||
|
||||
Use `tests/ui/update-all-references.sh` to automatically generate the
|
||||
`.fixed` file after running the tests.
|
||||
|
||||
### Edition 2018 tests
|
||||
[rustfix]: https://github.com/rust-lang/rustfix
|
||||
|
||||
## Edition 2018 tests
|
||||
|
||||
Some features require the 2018 edition to work (e.g. `async_await`), but
|
||||
compile-test tests run on the 2015 edition by default. To change this behavior
|
||||
add `// compile-flags: --edition 2018` at the top of the test file.
|
||||
add `// edition:2018` at the top of the test file (note that it's space-sensitive).
|
||||
|
||||
### Testing manually
|
||||
## Testing manually
|
||||
|
||||
Manually testing against an example file can be useful if you have added some
|
||||
`println!`s and the test suite output becomes unreadable. To try Clippy with
|
||||
|
@ -131,7 +131,7 @@ clippy-driver -- -L ./target/debug input.rs` from the working copy root.
|
|||
|
||||
With tests in place, let's have a look at implementing our lint now.
|
||||
|
||||
### Lint declaration
|
||||
## Lint declaration
|
||||
|
||||
Let's start by opening the new file created in the `clippy_lints` crate
|
||||
at `clippy_lints/src/foo_functions.rs`. That's the crate where all the
|
||||
|
@ -140,7 +140,7 @@ lint code is. This file has already imported some initial things we will need:
|
|||
```rust
|
||||
use rustc_lint::{EarlyLintPass, EarlyContext};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use syntax::ast::*;
|
||||
use rustc_ast::ast::*;
|
||||
```
|
||||
|
||||
The next step is to update the lint declaration. Lints are declared using the
|
||||
|
@ -167,12 +167,12 @@ declare_clippy_lint! {
|
|||
```
|
||||
|
||||
* The section of lines prefixed with `///` constitutes the lint documentation
|
||||
section. This is the default documentation style and will be displayed at
|
||||
https://rust-lang.github.io/rust-clippy/master/index.html.
|
||||
* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the [lint naming
|
||||
guidelines][lint_naming] here when naming your lint. In short, the name should
|
||||
state the thing that is being checked for and read well when used with
|
||||
`allow`/`warn`/`deny`.
|
||||
section. This is the default documentation style and will be displayed
|
||||
[like this][example_lint_page].
|
||||
* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the
|
||||
[lint naming guidelines][lint_naming] here when naming your lint.
|
||||
In short, the name should state the thing that is being checked for and
|
||||
read well when used with `allow`/`warn`/`deny`.
|
||||
* `pedantic` sets the lint level to `Allow`.
|
||||
The exact mapping can be found [here][category_level_mapping]
|
||||
* The last part should be a text that explains what exactly is wrong with the
|
||||
|
@ -199,14 +199,15 @@ automate everything. We will have to register our lint pass manually in the
|
|||
`register_plugins` function in `clippy_lints/src/lib.rs`:
|
||||
|
||||
```rust
|
||||
store.register_early_pass(box foo_functions::FooFunctions);
|
||||
store.register_early_pass(|| box foo_functions::FooFunctions);
|
||||
```
|
||||
|
||||
This should fix the `unknown clippy lint: clippy::foo_functions` error that we
|
||||
saw when we executed our tests the first time. The next decision we have to make
|
||||
is which lint pass our lint is going to need.
|
||||
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
|
||||
[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
|
||||
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
|
||||
[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
|
||||
|
||||
### Lint passes
|
||||
## Lint passes
|
||||
|
||||
Writing a lint that only checks for the name of a function means that we only
|
||||
have to deal with the AST and don't have to deal with the type system at all.
|
||||
|
@ -224,7 +225,10 @@ Since we don't need type information for checking the function name, we used
|
|||
`--pass=early` when running the new lint automation and all the imports were
|
||||
added accordingly.
|
||||
|
||||
### Emitting a lint
|
||||
[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
|
||||
[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
|
||||
|
||||
## Emitting a lint
|
||||
|
||||
With UI tests and the lint declaration in place, we can start working on the
|
||||
implementation of the lint logic.
|
||||
|
@ -233,7 +237,7 @@ Let's start by implementing the `EarlyLintPass` for our `FooFunctions`:
|
|||
|
||||
```rust
|
||||
impl EarlyLintPass for FooFunctions {
|
||||
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
|
||||
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
|
||||
// TODO: Emit lint here
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +259,7 @@ automatically. This is how it looks:
|
|||
|
||||
```rust
|
||||
impl EarlyLintPass for FooFunctions {
|
||||
fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
|
||||
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
FOO_FUNCTIONS,
|
||||
|
@ -269,20 +273,23 @@ impl EarlyLintPass for FooFunctions {
|
|||
|
||||
Running our UI test should now produce output that contains the lint message.
|
||||
|
||||
### Adding the lint logic
|
||||
[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn
|
||||
[diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
|
||||
|
||||
## Adding the lint logic
|
||||
|
||||
Writing the logic for your lint will most likely be different from our example,
|
||||
so this section is kept rather short.
|
||||
|
||||
Using the [`check_fn`][check_fn] method gives us access to [`FnKind`][fn_kind]
|
||||
that has two relevant variants for us `FnKind::ItemFn` and `FnKind::Method`.
|
||||
Both provide access to the name of the function/method via an [`Ident`][ident].
|
||||
that has the [`FnKind::Fn`] variant. It provides access to the name of the
|
||||
function/method via an [`Ident`][ident].
|
||||
|
||||
With that we can expand our `check_fn` method to:
|
||||
|
||||
```rust
|
||||
impl EarlyLintPass for FooFunctions {
|
||||
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
|
||||
fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
|
||||
if is_foo_fn(fn_kind) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
@ -307,9 +314,11 @@ In our example, `is_foo_fn` looks like:
|
|||
|
||||
fn is_foo_fn(fn_kind: FnKind<'_>) -> bool {
|
||||
match fn_kind {
|
||||
FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) => {
|
||||
ident.name == "foo"
|
||||
},
|
||||
FnKind::Fn(_, ident, ..) => {
|
||||
// check if `fn` name is `foo`
|
||||
ident.name.as_str() == "foo"
|
||||
}
|
||||
// ignore closures
|
||||
FnKind::Closure(..) => false
|
||||
}
|
||||
}
|
||||
|
@ -325,13 +334,18 @@ implementation is not violating any Clippy lints itself.
|
|||
That should be it for the lint implementation. Running `cargo test` should now
|
||||
pass.
|
||||
|
||||
### Author lint
|
||||
[fn_kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html
|
||||
[`FnKind::Fn`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html#variant.Fn
|
||||
[ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html
|
||||
|
||||
## Author lint
|
||||
|
||||
If you have trouble implementing your lint, there is also the internal `author`
|
||||
lint to generate Clippy code that detects the offending pattern. It does not
|
||||
work for all of the Rust syntax, but can give a good starting point.
|
||||
|
||||
The quickest way to use it, is the [Rust playground: play.rust-lang.org][Play].
|
||||
The quickest way to use it, is the
|
||||
[Rust playground: play.rust-lang.org][author_example].
|
||||
Put the code you want to lint into the editor and add the `#[clippy::author]`
|
||||
attribute above the item. Then run Clippy via `Tools -> Clippy` and you should
|
||||
see the generated code in the output below.
|
||||
|
@ -341,7 +355,9 @@ see the generated code in the output below.
|
|||
If the command was executed successfully, you can copy the code over to where
|
||||
you are implementing your lint.
|
||||
|
||||
### Documentation
|
||||
[author_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55
|
||||
|
||||
## Documentation
|
||||
|
||||
The final thing before submitting our PR is to add some documentation to our
|
||||
lint declaration.
|
||||
|
@ -374,11 +390,13 @@ declare_clippy_lint! {
|
|||
Once your lint is merged, this documentation will show up in the [lint
|
||||
list][lint_list].
|
||||
|
||||
### Running rustfmt
|
||||
[lint_list]: https://rust-lang.github.io/rust-clippy/master/index.html
|
||||
|
||||
[Rustfmt](https://github.com/rust-lang/rustfmt) is a tool for formatting Rust
|
||||
code according to style guidelines. Your code has to be formatted by `rustfmt`
|
||||
before a PR can be merged. Clippy uses nightly `rustfmt` in the CI.
|
||||
## Running rustfmt
|
||||
|
||||
[Rustfmt] is a tool for formatting Rust code according to style guidelines.
|
||||
Your code has to be formatted by `rustfmt` before a PR can be merged.
|
||||
Clippy uses nightly `rustfmt` in the CI.
|
||||
|
||||
It can be installed via `rustup`:
|
||||
|
||||
|
@ -389,13 +407,17 @@ rustup component add rustfmt --toolchain=nightly
|
|||
Use `cargo dev fmt` to format the whole codebase. Make sure that `rustfmt` is
|
||||
installed for the nightly toolchain.
|
||||
|
||||
### Debugging
|
||||
[Rustfmt]: https://github.com/rust-lang/rustfmt
|
||||
|
||||
If you want to debug parts of your lint implementation, you can use the `dbg!`
|
||||
## Debugging
|
||||
|
||||
If you want to debug parts of your lint implementation, you can use the [`dbg!`]
|
||||
macro anywhere in your code. Running the tests should then include the debug
|
||||
output in the `stdout` part.
|
||||
|
||||
### PR Checklist
|
||||
[`dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html
|
||||
|
||||
## PR Checklist
|
||||
|
||||
Before submitting your PR make sure you followed all of the basic requirements:
|
||||
|
||||
|
@ -408,7 +430,7 @@ Before submitting your PR make sure you followed all of the basic requirements:
|
|||
- [ ] Added lint documentation
|
||||
- [ ] Run `cargo dev fmt`
|
||||
|
||||
### Cheatsheet
|
||||
## Cheatsheet
|
||||
|
||||
Here are some pointers to things you are likely going to need for every lint:
|
||||
|
||||
|
@ -426,38 +448,26 @@ Here are some pointers to things you are likely going to need for every lint:
|
|||
For `EarlyLintPass` lints:
|
||||
|
||||
* [`EarlyLintPass`][early_lint_pass]
|
||||
* [`syntax::ast`][ast]
|
||||
* [`rustc_ast::ast`][ast]
|
||||
|
||||
For `LateLintPass` lints:
|
||||
|
||||
* [`LateLintPass`][late_lint_pass]
|
||||
* [`Ty::TyKind`][ty]
|
||||
|
||||
|
||||
While most of Clippy's lint utils are documented, most of rustc's internals lack
|
||||
documentation currently. This is unfortunate, but in most cases you can probably
|
||||
get away with copying things from existing similar lints. If you are stuck,
|
||||
don't hesitate to ask on Discord, IRC or in the issue/PR.
|
||||
don't hesitate to ask on [Discord] or in the issue/PR.
|
||||
|
||||
[lint_list]: https://rust-lang.github.io/rust-clippy/master/index.html
|
||||
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
|
||||
[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/bd23cb89ec0ea63403a17d3fc5e50c88e38dd54f/clippy_lints/src/lib.rs#L43
|
||||
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/a71acac1da7eaf667ab90a1d65d10e5cc4b80191/clippy_lints/src/lib.rs#L39
|
||||
[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.EarlyLintPass.html#method.check_fn
|
||||
[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.EarlyLintPass.html
|
||||
[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.LateLintPass.html
|
||||
[fn_kind]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/visit/enum.FnKind.html
|
||||
[diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
|
||||
[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs
|
||||
[ident]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/source_map/symbol/struct.Ident.html
|
||||
[span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
|
||||
[applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
|
||||
[if_chain]: https://docs.rs/if_chain/*/if_chain/
|
||||
[ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/sty/index.html
|
||||
[ast]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/index.html
|
||||
[from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
|
||||
[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/fn.in_external_macro.html
|
||||
[play]: https://play.rust-lang.org
|
||||
[author_example]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f093b986e80ad62f3b67a1f24f5e66e2
|
||||
[span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
|
||||
[applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
|
||||
[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
|
||||
[nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/
|
||||
[ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html
|
||||
[ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/sty/index.html
|
||||
[Discord]: https://discord.gg/rust-lang
|
||||
|
|
Loading…
Add table
Reference in a new issue