]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/mut_reference.rs
Auto merge of #3570 - muth:master, r=phansch
[rust.git] / clippy_lints / src / mut_reference.rs
1 // Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10 use crate::rustc::hir::*;
11 use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
12 use crate::rustc::ty::subst::Subst;
13 use crate::rustc::ty::{self, Ty};
14 use crate::rustc::{declare_tool_lint, lint_array};
15 use crate::utils::span_lint;
16
17 /// **What it does:** Detects giving a mutable reference to a function that only
18 /// requires an immutable reference.
19 ///
20 /// **Why is this bad?** The immutable reference rules out all other references
21 /// to the value. Also the code misleads about the intent of the call site.
22 ///
23 /// **Known problems:** None.
24 ///
25 /// **Example:**
26 /// ```rust
27 /// my_vec.push(&mut value)
28 /// ```
29 declare_clippy_lint! {
30     pub UNNECESSARY_MUT_PASSED,
31     style,
32     "an argument passed as a mutable reference although the callee only demands an immutable reference"
33 }
34
35 #[derive(Copy, Clone)]
36 pub struct UnnecessaryMutPassed;
37
38 impl LintPass for UnnecessaryMutPassed {
39     fn get_lints(&self) -> LintArray {
40         lint_array!(UNNECESSARY_MUT_PASSED)
41     }
42 }
43
44 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
45     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
46         match e.node {
47             ExprKind::Call(ref fn_expr, ref arguments) => {
48                 if let ExprKind::Path(ref path) = fn_expr.node {
49                     check_arguments(
50                         cx,
51                         arguments,
52                         cx.tables.expr_ty(fn_expr),
53                         &print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
54                     );
55                 }
56             },
57             ExprKind::MethodCall(ref path, _, ref arguments) => {
58                 let def_id = cx.tables.type_dependent_defs()[e.hir_id].def_id();
59                 let substs = cx.tables.node_substs(e.hir_id);
60                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
61                 check_arguments(cx, arguments, method_type, &path.ident.as_str())
62             },
63             _ => (),
64         }
65     }
66 }
67
68 fn check_arguments<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arguments: &[Expr], type_definition: Ty<'tcx>, name: &str) {
69     match type_definition.sty {
70         ty::FnDef(..) | ty::FnPtr(_) => {
71             let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
72             for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
73                 match parameter.sty {
74                     ty::Ref(_, _, MutImmutable)
75                     | ty::RawPtr(ty::TypeAndMut {
76                         mutbl: MutImmutable, ..
77                     }) => {
78                         if let ExprKind::AddrOf(MutMutable, _) = argument.node {
79                             span_lint(
80                                 cx,
81                                 UNNECESSARY_MUT_PASSED,
82                                 argument.span,
83                                 &format!("The function/method `{}` doesn't need a mutable reference", name),
84                             );
85                         }
86                     },
87                     _ => (),
88                 }
89             }
90         },
91         _ => (),
92     }
93 }