]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/escape.rs
Auto merge of #4551 - mikerite:fix-ice-reporting, r=llogiq
[rust.git] / clippy_lints / src / escape.rs
index 3f49cbdc0f2c6a419e4df968a45ed5341a1a8ef4..e174cdfb86033f92095752bcc83bb53de3dabc7d 100644 (file)
@@ -1,38 +1,38 @@
-use crate::utils::span_lint;
 use rustc::hir::intravisit as visit;
-use rustc::hir::*;
+use rustc::hir::{self, *};
 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::middle::expr_use_visitor::*;
 use rustc::middle::mem_categorization::{cmt_, Categorization};
 use rustc::ty::layout::LayoutOf;
 use rustc::ty::{self, Ty};
-use rustc::util::nodemap::NodeSet;
-use rustc::{declare_tool_lint, lint_array};
-use syntax::ast::NodeId;
+use rustc::util::nodemap::HirIdSet;
+use rustc::{declare_tool_lint, impl_lint_pass};
 use syntax::source_map::Span;
 
-pub struct Pass {
+use crate::utils::span_lint;
+
+#[derive(Copy, Clone)]
+pub struct BoxedLocal {
     pub too_large_for_stack: u64,
 }
 
-/// **What it does:** Checks for usage of `Box<T>` where an unboxed `T` would
-/// work fine.
-///
-/// **Why is this bad?** This is an unnecessary allocation, and bad for
-/// performance. It is only necessary to allocate if you wish to move the box
-/// into something.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn main() {
-///     let x = Box::new(1);
-///     foo(*x);
-///     println!("{}", *x);
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `Box<T>` where an unboxed `T` would
+    /// work fine.
+    ///
+    /// **Why is this bad?** This is an unnecessary allocation, and bad for
+    /// performance. It is only necessary to allocate if you wish to move the box
+    /// into something.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # fn foo(bar: usize) {}
+    /// let x = Box::new(1);
+    /// foo(*x);
+    /// println!("{}", *x);
+    /// ```
     pub BOXED_LOCAL,
     perf,
     "using `Box<T>` where unnecessary"
@@ -42,23 +42,15 @@ fn is_non_trait_box(ty: Ty<'_>) -> bool {
     ty.is_box() && !ty.boxed_ty().is_trait()
 }
 
-struct EscapeDelegate<'a, 'tcx: 'a> {
+struct EscapeDelegate<'a, 'tcx> {
     cx: &'a LateContext<'a, 'tcx>,
-    set: NodeSet,
+    set: HirIdSet,
     too_large_for_stack: u64,
 }
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(BOXED_LOCAL)
-    }
-
-    fn name(&self) -> &'static str {
-        "BoxedLocal"
-    }
-}
+impl_lint_pass!(BoxedLocal => [BOXED_LOCAL]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal {
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
@@ -68,9 +60,9 @@ fn check_fn(
         _: Span,
         hir_id: HirId,
     ) {
-        // If the method is an impl for a trait, don't warn
+        // If the method is an impl for a trait, don't warn.
         let parent_id = cx.tcx.hir().get_parent_item(hir_id);
-        let parent_node = cx.tcx.hir().find_by_hir_id(parent_id);
+        let parent_node = cx.tcx.hir().find(parent_id);
 
         if let Some(Node::Item(item)) = parent_node {
             if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.node {
@@ -80,13 +72,22 @@ fn check_fn(
 
         let mut v = EscapeDelegate {
             cx,
-            set: NodeSet::default(),
+            set: HirIdSet::default(),
             too_large_for_stack: self.too_large_for_stack,
         };
 
-        let fn_def_id = cx.tcx.hir().local_def_id_from_hir_id(hir_id);
+        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
         let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
-        ExprUseVisitor::new(&mut v, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).consume_body(body);
+        ExprUseVisitor::new(
+            &mut v,
+            cx.tcx,
+            fn_def_id,
+            cx.param_env,
+            region_scope_tree,
+            cx.tables,
+            None,
+        )
+        .consume_body(body);
 
         for node in v.set {
             span_lint(
@@ -99,10 +100,23 @@ fn check_fn(
     }
 }
 
+// TODO: Replace with Map::is_argument(..) when it's fixed
+fn is_argument(map: &hir::map::Map<'_>, id: HirId) -> bool {
+    match map.find(id) {
+        Some(Node::Binding(_)) => (),
+        _ => return false,
+    }
+
+    match map.find(map.get_parent_node(id)) {
+        Some(Node::Param(_)) => true,
+        _ => false,
+    }
+}
+
 impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
     fn consume(&mut self, _: HirId, _: Span, cmt: &cmt_<'tcx>, mode: ConsumeMode) {
         if let Categorization::Local(lid) = cmt.cat {
-            if let Move(DirectRefMove) = mode {
+            if let Move(DirectRefMove) | Move(CaptureMove) = mode {
                 // moved out or in. clearly can't be localized
                 self.set.remove(&lid);
             }
@@ -111,25 +125,26 @@ fn consume(&mut self, _: HirId, _: Span, cmt: &cmt_<'tcx>, mode: ConsumeMode) {
     fn matched_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: MatchMode) {}
     fn consume_pat(&mut self, consume_pat: &Pat, cmt: &cmt_<'tcx>, _: ConsumeMode) {
         let map = &self.cx.tcx.hir();
-        if map.is_argument(consume_pat.id) {
+        if is_argument(map, consume_pat.hir_id) {
             // Skip closure arguments
-            if let Some(Node::Expr(..)) = map.find(map.get_parent_node(consume_pat.id)) {
+            let parent_id = map.get_parent_node(consume_pat.hir_id);
+            if let Some(Node::Expr(..)) = map.find(map.get_parent_node(parent_id)) {
                 return;
             }
+
             if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
-                self.set.insert(consume_pat.id);
+                self.set.insert(consume_pat.hir_id);
             }
             return;
         }
         if let Categorization::Rvalue(..) = cmt.cat {
-            let id = map.hir_to_node_id(cmt.hir_id);
-            if let Some(Node::Stmt(st)) = map.find(map.get_parent_node(id)) {
+            if let Some(Node::Stmt(st)) = map.find(map.get_parent_node(cmt.hir_id)) {
                 if let StmtKind::Local(ref loc) = st.node {
                     if let Some(ref ex) = loc.init {
                         if let ExprKind::Box(..) = ex.node {
                             if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
                                 // let x = box (...)
-                                self.set.insert(consume_pat.id);
+                                self.set.insert(consume_pat.hir_id);
                             }
                             // TODO Box::new
                             // TODO vec![]
@@ -143,7 +158,7 @@ fn consume_pat(&mut self, consume_pat: &Pat, cmt: &cmt_<'tcx>, _: ConsumeMode) {
             if self.set.contains(&lid) {
                 // let y = x where x is known
                 // remove x, insert y
-                self.set.insert(consume_pat.id);
+                self.set.insert(consume_pat.hir_id);
                 self.set.remove(&lid);
             }
         }
@@ -159,32 +174,31 @@ fn borrow(
     ) {
         if let Categorization::Local(lid) = cmt.cat {
             match loan_cause {
-                // x.foo()
-                // Used without autodereffing (i.e. x.clone())
+                // `x.foo()`
+                // Used without autoderef-ing (i.e., `x.clone()`).
                 LoanCause::AutoRef |
 
-                // &x
-                // foo(&x) where no extra autoreffing is happening
+                // `&x`
+                // `foo(&x)` where no extra autoref-ing is happening.
                 LoanCause::AddrOf |
 
-                // `match x` can move
+                // `match x` can move.
                 LoanCause::MatchDiscriminant => {
                     self.set.remove(&lid);
                 }
 
-                // do nothing for matches, etc. These can't escape
+                // Do nothing for matches, etc. These can't escape.
                 _ => {}
             }
         }
     }
-    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
+    fn decl_without_init(&mut self, _: HirId, _: Span) {}
     fn mutate(&mut self, _: HirId, _: Span, _: &cmt_<'tcx>, _: MutateMode) {}
 }
 
 impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
     fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
-        // Large types need to be boxed to avoid stack
-        // overflows.
+        // Large types need to be boxed to avoid stack overflows.
         if ty.is_box() {
             self.cx.layout_of(ty.boxed_ty()).ok().map_or(0, |l| l.size.bytes()) > self.too_large_for_stack
         } else {