New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explain how Clippy and lints work #2687

Merged
merged 2 commits into from Apr 25, 2018
Jump to file or symbol
Failed to load files and symbols.
+61 −0
Diff settings

Always

Just for now

Copy path View file
@@ -147,6 +147,56 @@ enabled as a plugin:
#![plugin(clippy)]
```
### 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:
```rust
// ./clippy_lints/src/lib.rs
// ...
pub mod else_if_without_else;
// ...
pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
// ...
reg.register_early_lint_pass(box else_if_without_else::ElseIfWithoutElse);
// ...
reg.register_lint_group("clippy_restriction", vec![

This comment has been minimized.

@Manishearth

Manishearth Apr 21, 2018

Member

Worth mentioning that this code is autogenerated

This comment has been minimized.

@phansch

phansch Apr 22, 2018

Collaborator

Hm, I'm not sure I understand how that code would be autogenerated. It's a normal call to Registry.register_lint_group, no?

This comment has been minimized.

@llogiq

llogiq Apr 22, 2018

Collaborator

The util/update_lints.py script looks through the sources and collects all lint definitions to generate this part of lib.rs.

This comment has been minimized.

@phansch

phansch Apr 22, 2018

Collaborator

oh, that kind of autogenerated! I've always been modifying it manually until now.. Makes sense to add it 👍

// ...
else_if_without_else::ELSE_IF_WITHOUT_ELSE,
// ...
]);
}
```
The [`rustc_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 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 `util/update_lints.py` 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.
```rust
// ./clippy_lints/src/else_if_without_else.rs
use rustc::lint::*;
// ...
pub struct ElseIfWithoutElse;
// ...
impl EarlyLintPass for ElseIfWithoutElse {
// ... the functions needed, to make the lint work
}
```
The difference between `EarlyLintPass` and `LateLintPass` is that the methods of the `EarlyLintPass` trait only provide 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.
## Contributions
Contributions to Clippy should be made in the form of GitHub pull requests. Each pull request will
@@ -156,3 +206,14 @@ main tree or given feedback for changes that would be required.
All code in this repository is under the [Mozilla Public License, 2.0](https://www.mozilla.org/MPL/2.0/)
<!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md -->
[main_entry]: https://github.com/rust-lang-nursery/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/src/lib.rs#L14
[lint_crate]: https://github.com/rust-lang-nursery/rust-clippy/tree/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src
[lint_crate_entry]: https://github.com/rust-lang-nursery/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src/lib.rs
[else_if_without_else]: https://github.com/rust-lang-nursery/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/registry/struct.Registry.html
[reg_early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin/registry/struct.Registry.html#method.register_early_lint_pass
[reg_late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin/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
ProTip! Use n and p to navigate between commits in a pull request.