summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/book
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /src/tools/clippy/book
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/clippy/book')
-rw-r--r--src/tools/clippy/book/src/SUMMARY.md5
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md4
-rw-r--r--src/tools/clippy/book/src/development/defining_lints.md205
-rw-r--r--src/tools/clippy/book/src/development/emitting_lints.md217
-rw-r--r--src/tools/clippy/book/src/development/method_checking.md93
-rw-r--r--src/tools/clippy/book/src/development/speedtest.md8
-rw-r--r--src/tools/clippy/book/src/development/trait_checking.md105
-rw-r--r--src/tools/clippy/book/src/development/writing_tests.md218
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md38
9 files changed, 883 insertions, 10 deletions
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index 22fbdce75..b02457307 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -13,8 +13,13 @@
- [Development](development/README.md)
- [Basics](development/basics.md)
- [Adding Lints](development/adding_lints.md)
+ - [Defining Lints](development/defining_lints.md)
+ - [Writing tests](development/writing_tests.md)
- [Lint Passes](development/lint_passes.md)
+ - [Emitting lints](development/emitting_lints.md)
- [Type Checking](development/type_checking.md)
+ - [Trait Checking](development/trait_checking.md)
+ - [Method Checking](development/method_checking.md)
- [Macro Expansions](development/macro_expansions.md)
- [Common Tools](development/common_tools_writing_lints.md)
- [Infrastructure](development/infrastructure/README.md)
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index a0db80892..f6f0c95c7 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -161,8 +161,8 @@ The process of generating the `.stderr` file is the same, and prepending the
## 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] for that test. Rustfix will apply the suggestions
+will create a `.fixed` file by running [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.
diff --git a/src/tools/clippy/book/src/development/defining_lints.md b/src/tools/clippy/book/src/development/defining_lints.md
new file mode 100644
index 000000000..7c4aa5d45
--- /dev/null
+++ b/src/tools/clippy/book/src/development/defining_lints.md
@@ -0,0 +1,205 @@
+# 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.
+
+#### Lint types
+
+A lint type is the category of items and expressions in which your lint focuses on.
+
+As of the writing of this documentation update, there are 12 _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 types group together lints that share some common behaviors. For instance,
+`functions` groups together lints that deal with some aspects of functions in
+Rust, like definitions, signatures and attributes.
+
+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.
+
+## Lint name
+
+A good lint name is important, make sure to 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.
+
+---
+
+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=lint_name --pass=late --category=pedantic
+```
+
+There are two things to note here:
+
+1. `--pass`: 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. `--category`: If not provided, the `category` of this new lint will default
+ to `nursery`.
+
+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
+
+> **Note**: Lint types are listed in the ["Lint types"](#lint-types) section
+
+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.
+
+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
+```
+
+
+## The `define_clippy_lints` macro
+
+After `cargo dev new_lint`, you should see a macro with the name
+`define_clippy_lints`. It will be in the same file if you defined a standalone
+lint, and it will be in `mod.rs` if you defined a type-specific lint.
+
+The macro looks something like this:
+
+```rust
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// // Describe here what does the lint do.
+ ///
+ /// Triggers when detects...
+ ///
+ /// ### Why is this bad?
+ ///
+ /// // Describe why this pattern would be bad
+ ///
+ /// It can lead to...
+ ///
+ /// ### Example
+ /// ```rust
+ /// // example code where clippy issues a warning
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// // example code which does not raise clippy warning
+ /// ```
+ #[clippy::version = "1.70.0"] // <- In which version was this implemented, keep it up to date!
+ pub LINT_NAME, // <- The lint name IN_ALL_CAPS
+ pedantic, // <- The lint group
+ "default lint description" // <- A lint description, e.g. "A function has an unit return type."
+}
+```
+
+## 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.
+<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
+
+Without a call to one of `register_early_pass` or `register_late_pass`, the lint
+pass in question will not be run.
+
+
+[all_lints]: https://rust-lang.github.io/rust-clippy/master/
+[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
diff --git a/src/tools/clippy/book/src/development/emitting_lints.md b/src/tools/clippy/book/src/development/emitting_lints.md
new file mode 100644
index 000000000..a12f6aa91
--- /dev/null
+++ b/src/tools/clippy/book/src/development/emitting_lints.md
@@ -0,0 +1,217 @@
+# Emitting a lint
+
+Once we have [defined a lint](defining_lints.md), written [UI
+tests](writing_tests.md) and chosen [the lint pass](lint_passes.md) for the lint,
+we can begin the implementation of the lint logic so that we can emit it and
+gradually work towards a lint that behaves as expected.
+
+Note that we will not go into concrete implementation of a lint logic in this
+chapter. We will go into details in later chapters as well as in two examples of
+real Clippy lints.
+
+To emit a lint, we must implement a pass (see [Lint Passes](lint_passes.md)) for
+the lint that we have declared. In this example we'll implement a "late" lint,
+so take a look at the [LateLintPass][late_lint_pass] documentation, which
+provides an abundance of methods that we can implement for our lint.
+
+```rust
+pub trait LateLintPass<'tcx>: LintPass {
+ // Trait methods
+}
+```
+
+By far the most common method used for Clippy lints is [`check_expr`
+method][late_check_expr], this is because Rust is an expression language and,
+more often than not, the lint we want to work on must examine expressions.
+
+> _Note:_ If you don't fully understand what expressions are in Rust, take a
+> look at the official documentation on [expressions][rust_expressions]
+
+Other common ones include the [`check_fn` method][late_check_fn] and the
+[`check_item` method][late_check_item].
+
+### Emitting a lint
+
+Inside the trait method that we implement, we can write down the lint logic and
+emit the lint with suggestions.
+
+Clippy's [diagnostics] provides quite a few diagnostic functions that we can use
+to emit lints. Take a look at the documentation to pick one that suits your
+lint's needs the best. Some common ones you will encounter in the Clippy
+repository includes:
+
+- [`span_lint`]: Emits a lint without providing any other information
+- [`span_lint_and_note`]: Emits a lint and adds a note
+- [`span_lint_and_help`]: Emits a lint and provides a helpful message
+- [`span_lint_and_sugg`]: Emits a lint and provides a suggestion to fix the code
+- [`span_lint_and_then`]: Like `span_lint`, but allows for a lot of output
+ customization.
+
+```rust
+impl<'tcx> LateLintPass<'tcx> for LintName {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ // Imagine that `some_lint_expr_logic` checks for requirements for emitting the lint
+ if some_lint_expr_logic(expr) {
+ span_lint_and_help(
+ cx, // < The context
+ LINT_NAME, // < The name of the lint in ALL CAPS
+ expr.span, // < The span to lint
+ "message on why the lint is emitted",
+ None, // < An optional help span (to highlight something in the lint)
+ "message that provides a helpful suggestion",
+ );
+ }
+ }
+}
+```
+
+> Note: The message should be matter of fact and avoid capitalization and
+> punctuation. If multiple sentences are needed, the messages should probably be
+> split up into an error + a help / note / suggestion message.
+
+## Suggestions: Automatic fixes
+
+Some lints know what to change in order to fix the code. For example, the lint
+[`range_plus_one`][range_plus_one] warns for ranges where the user wrote `x..y +
+1` instead of using an [inclusive range][inclusive_range] (`x..=y`). The fix to
+this code would be changing the `x..y + 1` expression to `x..=y`. **This is
+where suggestions come in**.
+
+A suggestion is a change that the lint provides to fix the issue it is linting.
+The output looks something like this (from the example earlier):
+
+```text
+error: an inclusive range would be more readable
+ --> $DIR/range_plus_minus_one.rs:37:14
+ |
+LL | for _ in 1..1 + 1 {}
+ | ^^^^^^^^ help: use: `1..=1`
+```
+
+**Not all suggestions are always right**, some of them require human
+supervision, that's why we have [Applicability][applicability].
+
+Applicability indicates confidence in the correctness of the suggestion, some
+are always right (`Applicability::MachineApplicable`), but we use
+`Applicability::MaybeIncorrect` and others when talking about a suggestion that
+may be incorrect.
+
+### Example
+
+The same lint `LINT_NAME` but that emits a suggestion would look something like this:
+
+```rust
+impl<'tcx> LateLintPass<'tcx> for LintName {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ // Imagine that `some_lint_expr_logic` checks for requirements for emitting the lint
+ if some_lint_expr_logic(expr) {
+ span_lint_and_sugg( // < Note this change
+ cx,
+ LINT_NAME,
+ span,
+ "message on why the lint is emitted",
+ "use",
+ format!("foo + {} * bar", snippet(cx, expr.span, "<default>")), // < Suggestion
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
+```
+
+Suggestions generally use the [`format!`][format_macro] macro to interpolate the
+old values with the new ones. To get code snippets, use one of the `snippet*`
+functions from `clippy_utils::source`.
+
+## How to choose between notes, help messages and suggestions
+
+Notes are presented separately from the main lint message, they provide useful
+information that the user needs to understand why the lint was activated. They
+are the most helpful when attached to a span.
+
+Examples:
+
+### Notes
+
+```text
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+ --> $DIR/drop_forget_ref.rs:10:5
+ |
+10 | forget(&SomeStruct);
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::forget-ref` implied by `-D warnings`
+note: argument has type &SomeStruct
+ --> $DIR/drop_forget_ref.rs:10:12
+ |
+10 | forget(&SomeStruct);
+ | ^^^^^^^^^^^
+```
+
+### Help Messages
+
+Help messages are specifically to help the user. These are used in situation
+where you can't provide a specific machine applicable suggestion. They can also
+be attached to a span.
+
+Example:
+
+```text
+error: constant division of 0.0 with 0.0 will always result in NaN
+ --> $DIR/zero_div_zero.rs:6:25
+ |
+6 | let other_f64_nan = 0.0f64 / 0.0;
+ | ^^^^^^^^^^^^
+ |
+ = help: consider using `f64::NAN` if you would like a constant representing NaN
+```
+
+### Suggestions
+
+Suggestions are the most helpful, they are changes to the source code to fix the
+error. The magic in suggestions is that tools like `rustfix` can detect them and
+automatically fix your code.
+
+Example:
+
+```text
+error: This `.fold` can be more succinctly expressed as `.any`
+--> $DIR/methods.rs:390:13
+ |
+390 | let _ = (0..3).fold(false, |acc, x| acc || x > 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
+ |
+```
+
+### Snippets
+
+Snippets are pieces of the source code (as a string), they are extracted
+generally using the [`snippet`][snippet_fn] function.
+
+For example, if you want to know how an item looks (and you know the item's
+span), you could use `snippet(cx, span, "..")`.
+
+## Final: Run UI Tests to Emit the Lint
+
+Now, if we run our [UI test](writing_tests.md), we should see that Clippy now
+produces output that contains the lint message we designed.
+
+The next step is to implement the logic properly, which is a detail that we will
+cover in the next chapters.
+
+[diagnostics]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/diagnostics/index.html
+[late_check_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_expr
+[late_check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_fn
+[late_check_item]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_item
+[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
+[rust_expressions]: https://doc.rust-lang.org/reference/expressions.html
+[`span_lint`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint.html
+[`span_lint_and_note`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_note.html
+[`span_lint_and_help`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_help.html
+[`span_lint_and_sugg`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_sugg.html
+[`span_lint_and_then`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_then.html
+[range_plus_one]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
+[inclusive_range]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html
+[applicability]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_errors/enum.Applicability.html
+[snippet_fn]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/source/fn.snippet.html
+[format_macro]: https://doc.rust-lang.org/std/macro.format.html
diff --git a/src/tools/clippy/book/src/development/method_checking.md b/src/tools/clippy/book/src/development/method_checking.md
new file mode 100644
index 000000000..56d1be375
--- /dev/null
+++ b/src/tools/clippy/book/src/development/method_checking.md
@@ -0,0 +1,93 @@
+# Method Checking
+
+In some scenarios we might want to check for methods when developing
+a lint. There are two kinds of questions that we might be curious about:
+
+- Invocation: Does an expression call a specific method?
+- Definition: Does an `impl` define a method?
+
+## Checking if an `expr` is calling a specific method
+
+Suppose we have an `expr`, we can check whether it calls a specific
+method, e.g. `our_fancy_method`, by performing a pattern match on
+the [`ExprKind`] that we can access from `expr.kind`:
+
+```rust
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_span::sym;
+use clippy_utils::is_trait_method;
+
+impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ // Check our expr is calling a method with pattern matching
+ if let hir::ExprKind::MethodCall(path, _, [self_arg, ..]) = &expr.kind
+ // Check if the name of this method is `our_fancy_method`
+ && path.ident.name == sym!(our_fancy_method)
+ // We can check the type of the self argument whenever necessary.
+ // (It's necessary if we want to check that method is specifically belonging to a specific trait,
+ // for example, a `map` method could belong to user-defined trait instead of to `Iterator`)
+ // See the next section for more information.
+ && is_trait_method(cx, self_arg, sym::OurFancyTrait)
+ {
+ println!("`expr` is a method call for `our_fancy_method`");
+ }
+ }
+}
+```
+
+Take a closer look at the `ExprKind` enum variant [`MethodCall`] for more
+information on the pattern matching. As mentioned in [Define
+Lints](defining_lints.md#lint-types), the `methods` lint type is full of pattern
+matching with `MethodCall` in case the reader wishes to explore more.
+
+Additionally, we use the [`clippy_utils::sym!`][sym] macro to conveniently
+convert an input `our_fancy_method` into a `Symbol` and compare that symbol to
+the [`Ident`]'s name in the [`PathSegment`] in the [`MethodCall`].
+
+## Checking if a `impl` block implements a method
+
+While sometimes we want to check whether a method is being called or not, other
+times we want to know if our `Ty` defines a method.
+
+To check if our `impl` block defines a method `our_fancy_method`, we will
+utilize the [`check_impl_item`] method that is available in our beloved
+[`LateLintPass`] (for more information, refer to the ["Lint
+Passes"](lint_passes.md) chapter in the Clippy book). This method provides us
+with an [`ImplItem`] struct, which represents anything within an `impl` block.
+
+Let us take a look at how we might check for the implementation of
+`our_fancy_method` on a type:
+
+```rust
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::return_ty;
+use rustc_hir::{ImplItem, ImplItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_span::symbol::sym;
+
+impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
+ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
+ // Check if item is a method/function
+ if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
+ // Check the method is named `our_fancy_method`
+ && impl_item.ident.name == sym!(our_fancy_method)
+ // We can also check it has a parameter `self`
+ && signature.decl.implicit_self.has_implicit_self()
+ // We can go even further and even check if its return type is `String`
+ && is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::String)
+ {
+ println!("`our_fancy_method` is implemented!");
+ }
+ }
+}
+```
+
+[`check_impl_item`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_impl_item
+[`ExprKind`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/enum.ExprKind.html
+[`Ident`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/struct.Ident.html
+[`ImplItem`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_hir/hir/struct.ImplItem.html
+[`LateLintPass`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_lint/trait.LateLintPass.html
+[`MethodCall`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/enum.ExprKind.html#variant.MethodCall
+[`PathSegment`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/struct.PathSegment.html
+[sym]: https://doc.rust-lang.org/stable/nightly-rustc/clippy_utils/macro.sym.html
diff --git a/src/tools/clippy/book/src/development/speedtest.md b/src/tools/clippy/book/src/development/speedtest.md
index 0db718e6a..4ea1c8e5c 100644
--- a/src/tools/clippy/book/src/development/speedtest.md
+++ b/src/tools/clippy/book/src/development/speedtest.md
@@ -9,16 +9,12 @@ accessed by the `SPEEDTEST` (and `SPEEDTEST_*`) environment variables.
To do a simple speed test of a lint (e.g. `allow_attributes`), use this command.
```sh
-$ SPEEDTEST=ui TESTNAME="allow_attributes" cargo uitest -- --nocapture
+$ SPEEDTEST=ui TESTNAME="allow_attributes" cargo uitest
```
This will test all `ui` tests (`SPEEDTEST=ui`) whose names start with `allow_attributes`. By default, `SPEEDTEST` will
iterate your test 1000 times. But you can change this with `SPEEDTEST_ITERATIONS`.
```sh
-$ SPEEDTEST=toml SPEEDTEST_ITERATIONS=100 TESTNAME="semicolon_block" cargo uitest -- --nocapture
+$ SPEEDTEST=toml SPEEDTEST_ITERATIONS=100 TESTNAME="semicolon_block" cargo uitest
```
-
-> **WARNING**: Be sure to use `-- --nocapture` at the end of the command to see the average test time. If you don't
-> use `-- --nocapture` (e.g. `SPEEDTEST=ui` `TESTNAME="let_underscore_untyped" cargo uitest -- --nocapture`), this
-> will not show up.
diff --git a/src/tools/clippy/book/src/development/trait_checking.md b/src/tools/clippy/book/src/development/trait_checking.md
new file mode 100644
index 000000000..fb263922c
--- /dev/null
+++ b/src/tools/clippy/book/src/development/trait_checking.md
@@ -0,0 +1,105 @@
+# Trait Checking
+
+Besides [type checking](type_checking.md), we might want to examine if
+a specific type `Ty` implements certain trait when implementing a lint.
+There are three approaches to achieve this, depending on if the target trait
+that we want to examine has a [diagnostic item][diagnostic_items],
+[lang item][lang_items], or neither.
+
+## Using Diagnostic Items
+
+As explained in the [Rust Compiler Development Guide][rustc_dev_guide], diagnostic items
+are introduced for identifying types via [Symbols][symbol].
+
+For instance, if we want to examine whether an expression implements
+the `Iterator` trait, we could simply write the following code,
+providing the `LateContext` (`cx`), our expression at hand, and
+the symbol of the trait in question:
+
+```rust
+use clippy_utils::is_trait_method;
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_span::symbol::sym;
+
+impl LateLintPass<'_> for CheckIteratorTraitLint {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ let implements_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
+ implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
+ });
+ if implements_iterator {
+ // [...]
+ }
+
+ }
+}
+```
+
+> **Note**: Refer to [this index][symbol_index] for all the defined `Symbol`s.
+
+## Using Lang Items
+
+Besides diagnostic items, we can also use [`lang_items`][lang_items].
+Take a look at the documentation to find that `LanguageItems` contains
+all language items defined in the compiler.
+
+Using one of its `*_trait` method, we could obtain the [DefId] of any
+specific item, such as `Clone`, `Copy`, `Drop`, `Eq`, which are familiar
+to many Rustaceans.
+
+For instance, if we want to examine whether an expression `expr` implements
+`Drop` trait, we could access `LanguageItems` via our `LateContext`'s
+[TyCtxt], which provides a `lang_items` method that will return the id of
+`Drop` trait to us. Then, by calling Clippy utils function `implements_trait`
+we can check that the `Ty` of the `expr` implements the trait:
+
+```rust
+use clippy_utils::implements_trait;
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+
+impl LateLintPass<'_> for CheckDropTraitLint {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ let ty = cx.typeck_results().expr_ty(expr);
+ if cx.tcx.lang_items()
+ .drop_trait()
+ .map_or(false, |id| implements_trait(cx, ty, id, &[])) {
+ println!("`expr` implements `Drop` trait!");
+ }
+ }
+}
+```
+
+## Using Type Path
+
+If neither diagnostic item nor a language item is available, we can use
+[`clippy_utils::paths`][paths] with the `match_trait_method` to determine trait
+implementation.
+
+> **Note**: This approach should be avoided if possible, the best thing to do would be to make a PR to [`rust-lang/rust`][rust] adding a diagnostic item.
+
+Below, we check if the given `expr` implements the `Iterator`'s trait method `cloned` :
+
+```rust
+use clippy_utils::{match_trait_method, paths};
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+
+impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if match_trait_method(cx, expr, &paths::CORE_ITER_CLONED) {
+ println!("`expr` implements `CORE_ITER_CLONED` trait!");
+ }
+ }
+}
+```
+
+[DefId]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
+[diagnostic_items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
+[lang_items]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/lang_items/struct.LanguageItems.html
+[paths]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/paths.rs
+[rustc_dev_guide]: https://rustc-dev-guide.rust-lang.org/
+[symbol]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html
+[symbol_index]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/sym/index.html
+[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
+[rust]: https://github.com/rust-lang/rust
diff --git a/src/tools/clippy/book/src/development/writing_tests.md b/src/tools/clippy/book/src/development/writing_tests.md
new file mode 100644
index 000000000..8937e0d8e
--- /dev/null
+++ b/src/tools/clippy/book/src/development/writing_tests.md
@@ -0,0 +1,218 @@
+# Testing
+
+Developing lints for Clippy is a Test-Driven Development (TDD) process because
+our first task before implementing any logic for a new lint is to write some test cases.
+
+## Develop Lints with Tests
+
+When we develop Clippy, we enter a complex and chaotic realm full of
+programmatic issues, stylistic errors, illogical code and non-adherence to convention.
+Tests are the first layer of order we can leverage to define when and where
+we want a new lint to trigger or not.
+
+Moreover, writing tests first help Clippy developers to find a balance for
+the first iteration of and further enhancements for a lint.
+With test cases on our side, we will not have to worry about over-engineering
+a lint on its first version nor missing out some obvious edge cases of the lint.
+This approach empowers us to iteratively enhance each lint.
+
+## Clippy UI Tests
+
+We use **UI tests** for testing in Clippy. These UI tests check that the output
+of Clippy is exactly as we expect it to be. Each test is just a plain Rust file
+that contains the code we want to check.
+
+The output of Clippy is compared against a `.stderr` file. Note that you don't
+have to create this file yourself. We'll get to generating the `.stderr` files
+with the command [`cargo bless`](#cargo-bless) (seen later on).
+
+### Write Test Cases
+
+Let us now think about some tests for our imaginary `foo_functions` lint. We
+start by opening the test file `tests/ui/foo_functions.rs` that was created by
+`cargo dev new_lint`.
+
+Update the file with some examples to get started:
+
+```rust
+#![warn(clippy::foo_functions)] // < Add this, so the lint is guaranteed to be enabled in this file
+
+// Impl methods
+struct A;
+impl A {
+ pub fn fo(&self) {}
+ pub fn foo(&self) {} //~ ERROR: function called "foo"
+ pub fn food(&self) {}
+}
+
+// Default trait methods
+trait B {
+ fn fo(&self) {}
+ fn foo(&self) {} //~ ERROR: function called "foo"
+ fn food(&self) {}
+}
+
+// Plain functions
+fn fo() {}
+fn foo() {} //~ ERROR: function called "foo"
+fn food() {}
+
+fn main() {
+ // We also don't want to lint method calls
+ foo();
+ let a = A;
+ a.foo();
+}
+```
+
+Without actual lint logic to emit the lint when we see a `foo` function name,
+this test will just pass, because no lint will be emitted. However, we can now
+run the test with the following command:
+
+```sh
+$ TESTNAME=foo_functions cargo uitest
+```
+
+Clippy will compile and it will conclude with an `ok` for the tests:
+
+```
+...Clippy warnings and test outputs...
+test compile_test ... ok
+test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s
+```
+
+This is normal. After all, we wrote a bunch of Rust code but we haven't really
+implemented any logic for Clippy to detect `foo` functions and emit a lint.
+
+As we gradually implement our lint logic, we will keep running this UI test command.
+Clippy will begin outputting information that allows us to check if the output is
+turning into what we want it to be.
+
+### Example output
+
+As our `foo_functions` lint is tested, the output would look something like this:
+
+```
+failures:
+---- compile_test stdout ----
+normalized stderr:
+error: function called "foo"
+ --> $DIR/foo_functions.rs:6:12
+ |
+LL | pub fn foo(&self) {}
+ | ^^^
+ |
+ = note: `-D clippy::foo-functions` implied by `-D warnings`
+error: function called "foo"
+ --> $DIR/foo_functions.rs:13:8
+ |
+LL | fn foo(&self) {}
+ | ^^^
+error: function called "foo"
+ --> $DIR/foo_functions.rs:19:4
+ |
+LL | fn foo() {}
+ | ^^^
+error: aborting due to 3 previous errors
+```
+
+Note the *failures* label at the top of the fragment, we'll get rid of it
+(saving this output) in the next section.
+
+> _Note:_ You can run multiple test files by specifying a comma separated list:
+> `TESTNAME=foo_functions,bar_methods,baz_structs`.
+
+### `cargo bless`
+
+Once we are satisfied with the output, we need to run this command to
+generate or update the `.stderr` file for our lint:
+
+```sh
+$ TESTNAME=foo_functions cargo uibless
+```
+
+This writes the emitted lint suggestions and fixes to the `.stderr` file, with
+the reason for the lint, suggested fixes, and line numbers, etc.
+
+Running `TESTNAME=foo_functions cargo uitest` should pass then. When we commit
+our lint, we need to commit the generated `.stderr` files, too.
+
+In general, you should only commit files changed by `cargo bless` for the
+specific lint you are creating/editing.
+
+> _Note:_ If the generated `.stderr`, and `.fixed` files are empty,
+> they should be removed.
+
+## `toml` Tests
+
+Some lints can be configured through a `clippy.toml` file. Those configuration
+values are tested in `tests/ui-toml`.
+
+To add a new test there, create a new directory and add the files:
+
+- `clippy.toml`: Put here the configuration value you want to test.
+- `lint_name.rs`: A test file where you put the testing code, that should see a
+ different lint behavior according to the configuration set in the
+ `clippy.toml` file.
+
+The potential `.stderr` and `.fixed` files can again be generated with `cargo
+bless`.
+
+## Cargo Lints
+
+The process of testing is different for Cargo lints in that now we are
+interested in the `Cargo.toml` manifest file. In this case, we also need a
+minimal crate associated with that manifest. Those tests are generated in
+`tests/ui-cargo`.
+
+Imagine we have a new example lint that is named `foo_categories`, we can run:
+
+```sh
+$ cargo dev new_lint --name=foo_categories --pass=late --category=cargo
+```
+
+After running `cargo dev new_lint` we will find by default two new crates,
+each with its manifest file:
+
+* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the
+ new lint to raise an error.
+* `tests/ui-cargo/foo_categories/pass/Cargo.toml`: this file should not trigger
+ the lint.
+
+If you need more cases, you can copy one of those crates (under
+`foo_categories`) and rename it.
+
+The process of generating the `.stderr` file is the same as for other lints
+and prepending the `TESTNAME` variable to `cargo uitest` works for Cargo lints too.
+
+## Rustfix Tests
+
+If the lint you are working on is making use of structured suggestions,
+[`rustfix`] will apply the suggestions from the lint to the test file code and
+compare that to the contents of a `.fixed` file.
+
+Structured suggestions tell a user how to fix or re-write certain code that has
+been linted with [`span_lint_and_sugg`].
+
+Should `span_lint_and_sugg` be used to generate a suggestion, but not all
+suggestions lead to valid code, you can use the `//@no-rustfix` comment on top
+of the test file, to not run `rustfix` on that file.
+
+We'll talk about suggestions more in depth in a [later chapter](emitting_lints.md).
+
+Use `cargo bless` to automatically generate the `.fixed` file after running
+the tests.
+
+[`rustfix`]: https://github.com/rust-lang/rustfix
+[`span_lint_and_sugg`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_sugg.html
+
+## 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 your local modifications, run from the working copy root.
+
+```sh
+$ cargo dev lint input.rs
+```
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index caaad6d11..b980083f1 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -703,7 +703,7 @@ Minimum chars an ident can have, anything below or equal to this will be linted.
## `accept-comment-above-statement`
Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
-**Default Value:** `false` (`bool`)
+**Default Value:** `true` (`bool`)
---
**Affected lints:**
@@ -713,7 +713,7 @@ Whether to accept a safety comment to be placed above the statement containing t
## `accept-comment-above-attributes`
Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
-**Default Value:** `false` (`bool`)
+**Default Value:** `true` (`bool`)
---
**Affected lints:**
@@ -751,3 +751,37 @@ Which crates to allow absolute paths from
* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+## `allowed-dotfiles`
+Additional dotfiles (files or directories starting with a dot) to allow
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+---
+**Affected lints:**
+* [`path_ends_with_ext`](https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext)
+
+
+## `enforce-iter-loop-reborrow`
+#### Example
+```
+let mut vec = vec![1, 2, 3];
+let rmvec = &mut vec;
+for _ in rmvec.iter() {}
+for _ in rmvec.iter_mut() {}
+```
+
+Use instead:
+```
+let mut vec = vec![1, 2, 3];
+let rmvec = &mut vec;
+for _ in &*rmvec {}
+for _ in &mut *rmvec {}
+```
+
+**Default Value:** `false` (`bool`)
+
+---
+**Affected lints:**
+* [`explicit_iter_loop`](https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop)
+
+