]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/ptr.rs
Merge remote-tracking branch 'origin/master' into examples
[rust.git] / clippy_lints / src / ptr.rs
1 //! Checks for usage of  `&Vec[_]` and `&String`.
2
3 use rustc::hir::*;
4 use rustc::hir::map::NodeItem;
5 use rustc::lint::*;
6 use rustc::ty;
7 use syntax::ast::NodeId;
8 use utils::{match_path, match_type, paths, span_lint};
9
10 /// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless
11 /// the references are mutable.
12 ///
13 /// **Why is this bad?** Requiring the argument to be of the specific size makes the function less
14 /// useful for no benefit; slices in the form of `&[T]` or `&str` usually suffice and can be
15 /// obtained from other types, too.
16 ///
17 /// **Known problems:** None.
18 ///
19 /// **Example:**
20 /// ```rust
21 /// fn foo(&Vec<u32>) { .. }
22 /// ```
23 declare_lint! {
24     pub PTR_ARG,
25     Warn,
26     "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
27      instead, respectively"
28 }
29
30 /// **What it does:** This lint checks for equality comparisons with `ptr::null`
31 ///
32 /// **Why is this bad?** It's easier and more readable to use the inherent `.is_null()`
33 /// method instead
34 ///
35 /// **Known problems:** None.
36 ///
37 /// **Example:**
38 /// ```rust
39 /// if x == ptr::null { .. }
40 /// ```
41 declare_lint! {
42     pub CMP_NULL,
43     Warn,
44     "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead."
45 }
46
47
48 #[derive(Copy,Clone)]
49 pub struct PointerPass;
50
51 impl LintPass for PointerPass {
52     fn get_lints(&self) -> LintArray {
53         lint_array!(PTR_ARG, CMP_NULL)
54     }
55 }
56
57 impl LateLintPass for PointerPass {
58     fn check_item(&mut self, cx: &LateContext, item: &Item) {
59         if let ItemFn(ref decl, _, _, _, _, _) = item.node {
60             check_fn(cx, decl, item.id);
61         }
62     }
63
64     fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
65         if let ImplItemKind::Method(ref sig, _) = item.node {
66             if let Some(NodeItem(it)) = cx.tcx.map.find(cx.tcx.map.get_parent(item.id)) {
67                 if let ItemImpl(_, _, _, Some(_), _, _) = it.node {
68                     return; // ignore trait impls
69                 }
70             }
71             check_fn(cx, &sig.decl, item.id);
72         }
73     }
74
75     fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
76         if let MethodTraitItem(ref sig, _) = item.node {
77             check_fn(cx, &sig.decl, item.id);
78         }
79     }
80     
81     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
82         if let ExprBinary(ref op, ref l, ref r) = expr.node {
83             if (op.node == BiEq || op.node == BiNe) && (is_null_path(l) || is_null_path(r)) {
84                 span_lint(cx,
85                           CMP_NULL,
86                           expr.span,
87                           "Comparing with null is better expressed by the .is_null() method");
88             }
89         }
90     }
91 }
92
93 fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
94     let fn_ty = cx.tcx.node_id_to_type(fn_id).fn_sig().skip_binder();
95
96     for (arg, ty) in decl.inputs.iter().zip(&fn_ty.inputs) {
97         if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty {
98             if match_type(cx, ty, &paths::VEC) {
99                 span_lint(cx,
100                           PTR_ARG,
101                           arg.ty.span,
102                           "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
103                            with non-Vec-based slices. Consider changing the type to `&[...]`");
104             } else if match_type(cx, ty, &paths::STRING) {
105                 span_lint(cx,
106                           PTR_ARG,
107                           arg.ty.span,
108                           "writing `&String` instead of `&str` involves a new object where a slice will do. \
109                            Consider changing the type to `&str`");
110             }
111         }
112     }
113 }
114
115 fn is_null_path(expr: &Expr) -> bool {
116     if let ExprCall(ref pathexp, ref args) = expr.node {
117         if args.is_empty() {
118             if let ExprPath(_, ref path) = pathexp.node {
119                 return match_path(path, &paths::PTR_NULL) || match_path(path, &paths::PTR_NULL_MUT)
120             }
121         }
122     }
123     false
124 }