1 // Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
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.
10 //! Checks for needless address of operations (`&`)
12 //! This lint is **warn** by default
14 use crate::rustc::hir::{BindingAnnotation, Expr, ExprKind, Item, MutImmutable, Pat, PatKind};
15 use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
17 use crate::rustc::ty::adjustment::{Adjust, Adjustment};
18 use crate::rustc::{declare_tool_lint, lint_array};
19 use crate::rustc_errors::Applicability;
20 use crate::syntax::ast::NodeId;
21 use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
22 use if_chain::if_chain;
24 /// **What it does:** Checks for address of operations (`&`) that are going to
25 /// be dereferenced immediately by the compiler.
27 /// **Why is this bad?** Suggests that the receiver of the expression borrows
32 /// let x: &i32 = &&&&&&5;
35 /// **Known problems:** None.
36 declare_clippy_lint! {
39 "taking a reference that is going to be automatically dereferenced"
43 pub struct NeedlessBorrow {
44 derived_item: Option<NodeId>,
47 impl LintPass for NeedlessBorrow {
48 fn get_lints(&self) -> LintArray {
49 lint_array!(NEEDLESS_BORROW)
53 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
54 fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
55 if in_macro(e.span) || self.derived_item.is_some() {
58 if let ExprKind::AddrOf(MutImmutable, ref inner) = e.node {
59 if let ty::Ref(..) = cx.tables.expr_ty(inner).sty {
60 for adj3 in cx.tables.expr_adjustments(e).windows(3) {
62 kind: Adjust::Deref(_), ..
64 kind: Adjust::Deref(_), ..
66 kind: Adjust::Borrow(_),
74 "this expression borrows a reference that is immediately dereferenced \
77 if let Some(snippet) = snippet_opt(cx, inner.span) {
78 db.span_suggestion_with_applicability(
82 Applicability::MachineApplicable,
92 fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
93 if in_macro(pat.span) || self.derived_item.is_some() {
97 if let PatKind::Binding(BindingAnnotation::Ref, _, name, _) = pat.node;
98 if let ty::Ref(_, tam, mutbl) = cx.tables.pat_ty(pat).sty;
99 if mutbl == MutImmutable;
100 if let ty::Ref(_, _, mutbl) = tam.sty;
101 // only lint immutable refs, because borrowed `&mut T` cannot be moved out
102 if mutbl == MutImmutable;
108 "this pattern creates a reference to a reference",
110 if let Some(snippet) = snippet_opt(cx, name.span) {
111 db.span_suggestion_with_applicability(
115 Applicability::MachineApplicable,
124 fn check_item(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item) {
125 if item.attrs.iter().any(|a| a.check_name("automatically_derived")) {
126 debug_assert!(self.derived_item.is_none());
127 self.derived_item = Some(item.id);
131 fn check_item_post(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item) {
132 if let Some(id) = self.derived_item {
134 self.derived_item = None;