]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/needless_borrow.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / src / tools / clippy / clippy_lints / src / needless_borrow.rs
CommitLineData
f20569fa
XL
1//! Checks for needless address of operations (`&`)
2//!
3//! This lint is **warn** by default
4
5use crate::utils::{is_automatically_derived, snippet_opt, span_lint_and_then};
6use if_chain::if_chain;
7use rustc_errors::Applicability;
8use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind};
9use rustc_lint::{LateContext, LateLintPass};
10use rustc_middle::ty;
11use rustc_middle::ty::adjustment::{Adjust, Adjustment};
12use rustc_session::{declare_tool_lint, impl_lint_pass};
13use rustc_span::def_id::LocalDefId;
14
15declare_clippy_lint! {
16 /// **What it does:** Checks for address of operations (`&`) that are going to
17 /// be dereferenced immediately by the compiler.
18 ///
19 /// **Why is this bad?** Suggests that the receiver of the expression borrows
20 /// the expression.
21 ///
22 /// **Known problems:** None.
23 ///
24 /// **Example:**
25 /// ```rust
26 /// // Bad
27 /// let x: &i32 = &&&&&&5;
28 ///
29 /// // Good
30 /// let x: &i32 = &5;
31 /// ```
32 pub NEEDLESS_BORROW,
33 nursery,
34 "taking a reference that is going to be automatically dereferenced"
35}
36
37#[derive(Default)]
38pub struct NeedlessBorrow {
39 derived_item: Option<LocalDefId>,
40}
41
42impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);
43
44impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
45 fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
46 if e.span.from_expansion() || self.derived_item.is_some() {
47 return;
48 }
49 if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
50 if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
51 for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
52 if let [Adjustment {
53 kind: Adjust::Deref(_), ..
54 }, Adjustment {
55 kind: Adjust::Deref(_), ..
56 }, Adjustment {
57 kind: Adjust::Borrow(_),
58 ..
59 }] = *adj3
60 {
61 span_lint_and_then(
62 cx,
63 NEEDLESS_BORROW,
64 e.span,
65 &format!(
66 "this expression borrows a reference (`&{}`) that is immediately dereferenced \
67 by the compiler",
68 ty
69 ),
70 |diag| {
71 if let Some(snippet) = snippet_opt(cx, inner.span) {
72 diag.span_suggestion(
73 e.span,
74 "change this to",
75 snippet,
76 Applicability::MachineApplicable,
77 );
78 }
79 },
80 );
81 }
82 }
83 }
84 }
85 }
86 fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
87 if pat.span.from_expansion() || self.derived_item.is_some() {
88 return;
89 }
90 if_chain! {
91 if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
92 if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
93 if mutbl == Mutability::Not;
94 if let ty::Ref(_, _, mutbl) = *tam.kind();
95 // only lint immutable refs, because borrowed `&mut T` cannot be moved out
96 if mutbl == Mutability::Not;
97 then {
98 span_lint_and_then(
99 cx,
100 NEEDLESS_BORROW,
101 pat.span,
102 "this pattern creates a reference to a reference",
103 |diag| {
104 if let Some(snippet) = snippet_opt(cx, name.span) {
105 diag.span_suggestion(
106 pat.span,
107 "change this to",
108 snippet,
109 Applicability::MachineApplicable,
110 );
111 }
112 }
113 )
114 }
115 }
116 }
117
118 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
119 let attrs = cx.tcx.hir().attrs(item.hir_id());
120 if is_automatically_derived(attrs) {
121 debug_assert!(self.derived_item.is_none());
122 self.derived_item = Some(item.def_id);
123 }
124 }
125
126 fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
127 if let Some(id) = self.derived_item {
128 if item.def_id == id {
129 self.derived_item = None;
130 }
131 }
132 }
133}