diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a312a545d2..6a9f749e65a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -147,6 +147,55 @@ 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![ + // ... + 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. + +```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 +205,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/) + +[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