Skip to content

Commit b65e544

Browse files
committed
Auto merge of #10626 - blyxyas:book-trait_checking, r=flip1995
Clippy Book Chapter Updates Reborn: Trait Checking This PR adds a new chapter to the book: "Trait Checking". No major changes from the source (just some typos, re-phrasing, the usual). ## Notes - Does not require any other PR to be merged. - To talk about the whole project, please use the tracking issue for the project #10597 (It also contains a timeline, discussions and more information) changelog: Add a new "Trait Checking" chapter to the book
2 parents 7cf96da + e1a3f63 commit b65e544

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

book/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- [Lint Passes](development/lint_passes.md)
1919
- [Emitting lints](development/emitting_lints.md)
2020
- [Type Checking](development/type_checking.md)
21+
- [Trait Checking](development/trait_checking.md)
2122
- [Method Checking](development/method_checking.md)
2223
- [Macro Expansions](development/macro_expansions.md)
2324
- [Common Tools](development/common_tools_writing_lints.md)
+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Trait Checking
2+
3+
Besides [type checking](type_checking.md), we might want to examine if
4+
a specific type `Ty` implements certain trait when implementing a lint.
5+
There are three approaches to achieve this, depending on if the target trait
6+
that we want to examine has a [diagnostic item][diagnostic_items],
7+
[lang item][lang_items], or neither.
8+
9+
## Using Diagnostic Items
10+
11+
As explained in the [Rust Compiler Development Guide][rustc_dev_guide], diagnostic items
12+
are introduced for identifying types via [Symbols][symbol].
13+
14+
For instance, if we want to examine whether an expression implements
15+
the `Iterator` trait, we could simply write the following code,
16+
providing the `LateContext` (`cx`), our expression at hand, and
17+
the symbol of the trait in question:
18+
19+
```rust
20+
use clippy_utils::is_trait_method;
21+
use rustc_hir::Expr;
22+
use rustc_lint::{LateContext, LateLintPass};
23+
use rustc_span::symbol::sym;
24+
25+
impl LateLintPass<'_> for CheckIteratorTraitLint {
26+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
27+
let implements_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
28+
implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
29+
});
30+
if implements_iterator {
31+
// [...]
32+
}
33+
34+
}
35+
}
36+
```
37+
38+
> **Note**: Refer to [this index][symbol_index] for all the defined `Symbol`s.
39+
40+
## Using Lang Items
41+
42+
Besides diagnostic items, we can also use [`lang_items`][lang_items].
43+
Take a look at the documentation to find that `LanguageItems` contains
44+
all language items defined in the compiler.
45+
46+
Using one of its `*_trait` method, we could obtain the [DefId] of any
47+
specific item, such as `Clone`, `Copy`, `Drop`, `Eq`, which are familiar
48+
to many Rustaceans.
49+
50+
For instance, if we want to examine whether an expression `expr` implements
51+
`Drop` trait, we could access `LanguageItems` via our `LateContext`'s
52+
[TyCtxt], which provides a `lang_items` method that will return the id of
53+
`Drop` trait to us. Then, by calling Clippy utils function `implements_trait`
54+
we can check that the `Ty` of the `expr` implements the trait:
55+
56+
```rust
57+
use clippy_utils::implements_trait;
58+
use rustc_hir::Expr;
59+
use rustc_lint::{LateContext, LateLintPass};
60+
61+
impl LateLintPass<'_> for CheckDropTraitLint {
62+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
63+
let ty = cx.typeck_results().expr_ty(expr);
64+
if cx.tcx.lang_items()
65+
.drop_trait()
66+
.map_or(false, |id| implements_trait(cx, ty, id, &[])) {
67+
println!("`expr` implements `Drop` trait!");
68+
}
69+
}
70+
}
71+
```
72+
73+
## Using Type Path
74+
75+
If neither diagnostic item nor a language item is available, we can use
76+
[`clippy_utils::paths`][paths] with the `match_trait_method` to determine trait
77+
implementation.
78+
79+
> **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.
80+
81+
Below, we check if the given `expr` implements the `Iterator`'s trait method `cloned` :
82+
83+
```rust
84+
use clippy_utils::{match_trait_method, paths};
85+
use rustc_hir::Expr;
86+
use rustc_lint::{LateContext, LateLintPass};
87+
88+
impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
89+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
90+
if match_trait_method(cx, expr, &paths::CORE_ITER_CLONED) {
91+
println!("`expr` implements `CORE_ITER_CLONED` trait!");
92+
}
93+
}
94+
}
95+
```
96+
97+
[DefId]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
98+
[diagnostic_items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
99+
[lang_items]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/lang_items/struct.LanguageItems.html
100+
[paths]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/paths.rs
101+
[rustc_dev_guide]: https://rustc-dev-guide.rust-lang.org/
102+
[symbol]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html
103+
[symbol_index]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/sym/index.html
104+
[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
105+
[rust]: https://github.com/rust-lang/rust

0 commit comments

Comments
 (0)