about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--book/src/SUMMARY.md1
-rw-r--r--book/src/development/defining_lints.md161
2 files changed, 162 insertions, 0 deletions
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index 22fbdce75e8..f6378b1fb90 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -13,6 +13,7 @@
 - [Development](development/README.md)
     - [Basics](development/basics.md)
     - [Adding Lints](development/adding_lints.md)
+    - [Defining Lints](development/defining_lints.md)
     - [Lint Passes](development/lint_passes.md)
     - [Type Checking](development/type_checking.md)
     - [Macro Expansions](development/macro_expansions.md)
diff --git a/book/src/development/defining_lints.md b/book/src/development/defining_lints.md
new file mode 100644
index 00000000000..17e4c1a1181
--- /dev/null
+++ b/book/src/development/defining_lints.md
@@ -0,0 +1,161 @@
+# Define New Lints
+
+The first step in the journey of a new lint is the definition
+and registration of the lint in Clippy's codebase.
+We can use the Clippy dev tools to handle this step since setting up the 
+lint involves some boilerplate code.
+
+In our example, we're going to create a lint to detect functions named `foo` because it is a highly non-descriptive name for a function, so we want to trigger this and fix it early in the development process.
+
+## Lint name
+
+A good lint name is important, it is usually given by the issue you're fixing (in the **Lint name** field). If you're unsure if the name you chose fits the lint, you can check the [lint naming guidelines][lint_naming]. Don't worry, if the lint name doesn't fit, a Clippy team member will alert you in the PR process.
+
+If you're still unsure, you can ask on the [Zulip] or on the Github issue / PR.
+
+---
+
+We'll name our example lint that detects functions named "foo" `foo_functions`. Check the [lint naming guidelines][lint_naming] to see why this name makes sense.
+
+## Add and Register the Lint
+
+Now that a name is chosen, we shall register `foo_functions` as a lint to the codebase.
+There are two ways to register a lint.
+
+### Standalone
+
+If you believe that this new lint is a standalone lint (that doesn't belong to any specific [type](#lint-types) like `functions` or `loops`), you can run the following
+command in your Clippy project:
+
+```sh
+$ cargo dev new_lint --name=foo_functions --pass=late --category=pedantic
+```
+
+There are two things to note here:
+
+1. We set `--pass=late` in this command to do a late lint pass. The alternative
+is an `early` lint pass. We will discuss this difference in a later chapter.
+<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
+2. If not provided, the `category` of this new lint will default to `nursery`.
+See Clippy's [lint types](../lints.md) for more information on categories.
+
+The `cargo dev new_lint` command will create a new file: `clippy_lints/src/foo_functions.rs`
+as well as [register the lint](#lint-registration).
+
+Overall, you should notice that the following files are modified or created:
+
+```sh
+$ git status
+On branch foo_functions
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git restore <file>..." to discard changes in working directory)
+	modified:   CHANGELOG.md
+	modified:   clippy_lints/src/lib.register_lints.rs
+	modified:   clippy_lints/src/lib.register_pedantic.rs
+	modified:   clippy_lints/src/lib.rs
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+	clippy_lints/src/foo_functions.rs
+	tests/ui/foo_functions.rs
+```
+
+### Specific Type
+
+If you believe that this new lint belongs to a specific type of lints,
+you can run `cargo dev new_lint` with a `--type` option.
+
+Since our `foo_functions` lint is related to function calls, one could
+argue that we should put it into a group of lints that detect some behaviors
+of functions, we can put it in the `functions` group.
+
+Let's run the following command in your Clippy project:
+
+```sh
+$ cargo dev new_lint --name=foo_functions --type=functions --category=pedantic
+```
+
+This command will create, among other things, a new file:
+`clippy_lints/src/{type}/foo_functions.rs`.
+In our case, the path will be `clippy_lints/src/functions/foo_functions.rs`.
+
+Notice how this command has a `--type` flag instead of `--pass`. Unlike a standalone
+definition, this lint won't be registered in the traditional sense. Instead, you will
+call your lint from within the type's lint pass, found in `clippy_lints/src/{type}/mod.rs`.
+
+A _type_ is just the name of a directory in `clippy_lints/src`, like `functions` in
+the example command. Clippy groups together some lints that share common behaviors,
+so if your lint falls into one, it would be best to add it to that type.
+Read more about [lint types](#lint-types) below.
+
+Overall, you should notice that the following files are modified or created:
+
+```sh
+$ git status
+On branch foo_functions
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git restore <file>..." to discard changes in working directory)
+	modified:   CHANGELOG.md
+	modified:   clippy_lints/src/declared_lints.rs
+	modified:   clippy_lints/src/functions/mod.rs
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+	clippy_lints/src/functions/foo_functions.rs
+	tests/ui/foo_functions.rs
+```
+
+## Lint registration
+
+If we run the `cargo dev new_lint` command for a new lint,
+the lint will be automatically registered and there is nothing more to do.
+
+However, sometimes we might want to declare a new lint by hand.
+In this case, we'd use `cargo dev update_lints` command afterwards.
+
+When a lint is manually declared, we might need to register the lint pass
+manually in the `register_plugins` function in `clippy_lints/src/lib.rs`:
+
+```rust
+store.register_late_pass(|| Box::new(foo_functions::FooFunctions));
+```
+
+As you might have guessed, where there's something late, there is something early:
+in Clippy there is a `register_early_pass` method as well.
+More on early vs. late passes in a later chapter.
+
+Without a call to one of `register_early_pass` or `register_late_pass`,
+the lint pass in question will not be run.
+
+## Lint types
+
+As of the writing of this documentation update, there are 12 categories (a.k.a. _types_)
+of lints besides the numerous standalone lints living under `clippy_lints/src/`:
+
+- `cargo`
+- `casts`
+- `functions`
+- `loops`
+- `matches`
+- `methods`
+- `misc_early`
+- `operators`
+- `transmute`
+- `types`
+- `unit_types`
+- `utils / internal` (Clippy internal lints)
+
+These categories group together lints that share some common behaviors.
+For instance, as we have mentioned earlier, `functions` groups together lints
+that deal with some aspects of function calls in Rust.
+
+For more information, feel free to compare the lint files under any category
+with [All Clippy lints][all_lints] or
+ask one of the maintainers.
+
+[all_lints]: https://rust-lang.github.io/rust-clippy/master/
+[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
+[clippy_team_members]: https://www.rust-lang.org/governance/teams/dev-tools#Clippy%20team
+[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy
\ No newline at end of file