]> git.lizzy.rs Git - rust.git/blob - doc/common_tools_writing_lints.md
Rename the crates in source code
[rust.git] / doc / common_tools_writing_lints.md
1 # Common tools for writing lints
2
3 You may need following tooltips to catch up with common operations.
4
5 - [Common tools for writing lints](#common-tools-for-writing-lints)
6   - [Retrieving the type of an expression](#retrieving-the-type-of-an-expression)
7   - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait)
8   - [Dealing with macros](#dealing-with-macros)
9
10 Useful Rustc dev guide links:
11 - [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation)
12 - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html)
13 - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html)
14
15 # Retrieving the type of an expression
16
17 Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for example to answer following questions:
18
19 - which type does this expression correspond to (using its [`TyKind`][TyKind])?
20 - is it a sized type? 
21 - is it a primitive type?
22 - does it implement a trait?
23
24 This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct, 
25 that gives you access to the underlying structure [`TyS`][TyS].
26
27 Example of use:
28 ```rust
29 impl LateLintPass<'_, '_> for MyStructLint {
30     fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
31         // Get type of `expr`
32         let ty = cx.tables.expr_ty(expr);
33         // Match its kind to enter its type
34         match ty.kind {
35             ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"),
36             _ => ()
37         }
38     }
39 }
40 ```
41
42 Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method 
43 to retrieve a type from a pattern.
44
45 Two noticeable items here:
46 - `cx` is the lint context [`LateContext`][LateContext]. 
47   The two most useful data structures in this context are `tcx` and `tables`, 
48   allowing us to jump to type definitions and other compilation stages such as HIR.
49 - `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step, 
50   it includes useful information such as types of expressions, ways to resolve methods and so on.
51
52 # Checking if a type implements a specific trait
53
54 There are two ways to do this, depending if the target trait is part of lang items.
55
56 ```rust
57 use crate::utils::{implements_trait, match_trait_method, paths};
58
59 impl LateLintPass<'_, '_> for MyStructLint {
60     fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
61         // 1. Using expression and Clippy's convenient method
62         // we use `match_trait_method` function from Clippy's toolbox
63         if match_trait_method(cx, expr, &paths::INTO) {
64             // `expr` implements `Into` trait
65         }
66
67         // 2. Using type context `TyCtxt`
68         let ty = cx.tables.expr_ty(expr);
69         if cx.tcx.lang_items()
70             // we are looking for the `DefId` of `Drop` trait in lang items
71             .drop_trait()
72             // then we use it with our type `ty` by calling `implements_trait` from Clippy's utils
73             .map_or(false, |id| implements_trait(cx, ty, id, &[])) {
74                 // `expr` implements `Drop` trait
75             }
76     }
77 }
78 ```
79
80 > Prefer using lang items, if the target trait is available there.
81
82 A list of defined paths for Clippy can be found in [paths.rs][paths]
83
84 We access lang items through the type context `tcx`. `tcx` is of type [`TyCtxt`][TyCtxt] and is defined in the `rustc_middle` crate.
85
86 # Dealing with macros
87
88 There are several helpers in Clippy's utils to deal with macros:
89
90 - `in_macro()`: detect if the given span is expanded by a macro
91
92 You may want to use this for example to not start linting in any macro.
93
94 ```rust
95 macro_rules! foo {
96     ($param:expr) => {
97         match $param {
98             "bar" => println!("whatever"),
99             _ => ()
100         }
101     };
102 }
103
104 foo!("bar");
105
106 // if we lint the `match` of `foo` call and test its span
107 assert_eq!(in_macro(match_span), true);
108 ```
109
110 - `in_external_macro()`: detect if the given span is from an external macro, defined in a foreign crate
111
112 You may want to use it for example to not start linting in macros from other crates
113
114 ```rust
115 #[macro_use]
116 extern crate a_crate_with_macros;
117
118 // `foo` is defined in `a_crate_with_macros`
119 foo!("bar");
120
121 // if we lint the `match` of `foo` call and test its span
122 assert_eq!(in_external_macro(cx.sess(), match_span), true);
123 ```
124
125 - `differing_macro_contexts()`: returns true if the two given spans are not from the same context
126
127 ```rust
128 macro_rules! m {
129     ($a:expr, $b:expr) => {
130         if $a.is_some() {
131             $b;
132         }
133     }
134 }
135
136 let x: Option<u32> = Some(42);
137 m!(x, x.unwrap());
138
139 // These spans are not from the same context
140 // x.is_some() is from inside the macro
141 // x.unwrap() is from outside the macro
142 assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
143 ```
144
145 [TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html
146 [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html
147 [TypeckTables]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html
148 [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html#method.expr_ty
149 [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html
150 [TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
151 [pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckTables.html#method.pat_ty
152 [paths]: ../clippy_lints/src/utils/paths.rs