about summary refs log tree commit diff
path: root/src/tools/clippy/clippy_utils
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-02-09 19:21:17 +0100
committerGitHub <noreply@github.com>2024-02-09 19:21:17 +0100
commit5250abaeb84df7407bf9a2d887cbd30e1b2f96d0 (patch)
tree369412322fc24f7eb2ab3098a5fe63290d10c64a /src/tools/clippy/clippy_utils
parentc874b1a42435e2a7ec249861271aad18350d7af6 (diff)
parent4ec9eec9e83fb6a19b899247357e3d5dabfebc78 (diff)
downloadrust-5250abaeb84df7407bf9a2d887cbd30e1b2f96d0.tar.gz
rust-5250abaeb84df7407bf9a2d887cbd30e1b2f96d0.zip
Rollup merge of #120806 - flip1995:clippy-subtree-update, r=Manishearth
Clippy subtree update

r? `@Manishearth`
Diffstat (limited to 'src/tools/clippy/clippy_utils')
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs359
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs29
3 files changed, 211 insertions, 179 deletions
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index b8869eedf52..c7454fa3328 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.77"
+version = "0.1.78"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index d2bc49d1e29..6a33e11be46 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(array_chunks)]
 #![feature(box_patterns)]
+#![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
@@ -81,6 +82,7 @@ use core::mem;
 use core::ops::ControlFlow;
 use std::collections::hash_map::Entry;
 use std::hash::BuildHasherDefault;
+use std::iter::{once, repeat};
 use std::sync::{Mutex, MutexGuard, OnceLock};
 
 use itertools::Itertools;
@@ -90,6 +92,7 @@ use rustc_data_structures::packed::Pu128;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
+use rustc_hir::definitions::{DefPath, DefPathData};
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
@@ -108,8 +111,8 @@ use rustc_middle::ty::binding::BindingMode;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    self as rustc_ty, Binder, BorrowKind, ClosureKind, FloatTy, IntTy, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeAndMut,
-    TypeVisitableExt, UintTy, UpvarCapture,
+    self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv,
+    ParamEnvAnd, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -120,10 +123,7 @@ use visitors::Visitable;
 
 use crate::consts::{constant, mir_to_const, Constant};
 use crate::higher::Range;
-use crate::ty::{
-    adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
-    ty_is_fn_once_param,
-};
+use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
 use crate::visitors::for_each_expr;
 
 use rustc_middle::hir::nested_filter;
@@ -1359,46 +1359,12 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
     for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
         match node {
             Node::Expr(e) => match e.kind {
-                ExprKind::Closure { .. } => {
+                ExprKind::Closure { .. }
                     if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()
-                        && subs.as_closure().kind() == ClosureKind::FnOnce
-                    {
-                        continue;
-                    }
-                    let is_once = walk_to_expr_usage(cx, e, |node, id| {
-                        let Node::Expr(e) = node else {
-                            return None;
-                        };
-                        match e.kind {
-                            ExprKind::Call(f, _) if f.hir_id == id => Some(()),
-                            ExprKind::Call(f, args) => {
-                                let i = args.iter().position(|arg| arg.hir_id == id)?;
-                                let sig = expr_sig(cx, f)?;
-                                let predicates = sig
-                                    .predicates_id()
-                                    .map_or(cx.param_env, |id| cx.tcx.param_env(id))
-                                    .caller_bounds();
-                                sig.input(i).and_then(|ty| {
-                                    ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
-                                })
-                            },
-                            ExprKind::MethodCall(_, receiver, args, _) => {
-                                let i = std::iter::once(receiver)
-                                    .chain(args.iter())
-                                    .position(|arg| arg.hir_id == id)?;
-                                let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
-                                let ty = cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i];
-                                ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
-                            },
-                            _ => None,
-                        }
-                    })
-                    .is_some();
-                    if !is_once {
-                        return Some(e);
-                    }
-                },
-                ExprKind::Loop(..) => return Some(e),
+                        && subs.as_closure().kind() == ClosureKind::FnOnce => {},
+
+                // Note: A closure's kind is determined by how it's used, not it's captures.
+                ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e),
                 _ => (),
             },
             Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
@@ -2596,26 +2562,30 @@ pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
             && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
 }
 
-/// Walks the HIR tree from the given expression, up to the node where the value produced by the
-/// expression is consumed. Calls the function for every node encountered this way until it returns
-/// `Some`.
+/// Walks up the HIR tree from the given expression in an attempt to find where the value is
+/// consumed.
+///
+/// Termination has three conditions:
+/// - The given function returns `Break`. This function will return the value.
+/// - The consuming node is found. This function will return `Continue(use_node, child_id)`.
+/// - No further parent nodes are found. This will trigger a debug assert or return `None`.
 ///
-/// This allows walking through `if`, `match`, `break`, block expressions to find where the value
-/// produced by the expression is consumed.
+/// This allows walking through `if`, `match`, `break`, and block expressions to find where the
+/// value produced by the expression is consumed.
 pub fn walk_to_expr_usage<'tcx, T>(
     cx: &LateContext<'tcx>,
     e: &Expr<'tcx>,
-    mut f: impl FnMut(Node<'tcx>, HirId) -> Option<T>,
-) -> Option<T> {
+    mut f: impl FnMut(HirId, Node<'tcx>, HirId) -> ControlFlow<T>,
+) -> Option<ControlFlow<T, (Node<'tcx>, HirId)>> {
     let map = cx.tcx.hir();
     let mut iter = map.parent_iter(e.hir_id);
     let mut child_id = e.hir_id;
 
     while let Some((parent_id, parent)) = iter.next() {
-        if let Some(x) = f(parent, child_id) {
-            return Some(x);
+        if let ControlFlow::Break(x) = f(parent_id, parent, child_id) {
+            return Some(ControlFlow::Break(x));
         }
-        let parent = match parent {
+        let parent_expr = match parent {
             Node::Expr(e) => e,
             Node::Block(Block { expr: Some(body), .. }) | Node::Arm(Arm { body, .. }) if body.hir_id == child_id => {
                 child_id = parent_id;
@@ -2625,18 +2595,19 @@ pub fn walk_to_expr_usage<'tcx, T>(
                 child_id = parent_id;
                 continue;
             },
-            _ => return None,
+            _ => return Some(ControlFlow::Continue((parent, child_id))),
         };
-        match parent.kind {
+        match parent_expr.kind {
             ExprKind::If(child, ..) | ExprKind::Match(child, ..) if child.hir_id != child_id => child_id = parent_id,
             ExprKind::Break(Destination { target_id: Ok(id), .. }, _) => {
                 child_id = id;
                 iter = map.parent_iter(id);
             },
-            ExprKind::Block(..) => child_id = parent_id,
-            _ => return None,
+            ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = parent_id,
+            _ => return Some(ControlFlow::Continue((parent, child_id))),
         }
     }
+    debug_assert!(false, "no parent node found for `{child_id:?}`");
     None
 }
 
@@ -2680,6 +2651,8 @@ pub enum ExprUseNode<'tcx> {
     Callee,
     /// Access of a field.
     FieldAccess(Ident),
+    Expr,
+    Other,
 }
 impl<'tcx> ExprUseNode<'tcx> {
     /// Checks if the value is returned from the function.
@@ -2756,144 +2729,104 @@ impl<'tcx> ExprUseNode<'tcx> {
                 let sig = cx.tcx.fn_sig(id).skip_binder();
                 Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
             },
-            Self::Local(_) | Self::FieldAccess(..) | Self::Callee => None,
+            Self::Local(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None,
         }
     }
 }
 
 /// Gets the context an expression's value is used in.
-#[expect(clippy::too_many_lines)]
 pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<ExprUseCtxt<'tcx>> {
     let mut adjustments = [].as_slice();
     let mut is_ty_unified = false;
     let mut moved_before_use = false;
     let ctxt = e.span.ctxt();
-    walk_to_expr_usage(cx, e, &mut |parent, child_id| {
-        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
+    walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| {
         if adjustments.is_empty()
             && let Node::Expr(e) = cx.tcx.hir_node(child_id)
         {
             adjustments = cx.typeck_results().expr_adjustments(e);
         }
-        match parent {
-            Node::Local(l) if l.span.ctxt() == ctxt => Some(ExprUseCtxt {
-                node: ExprUseNode::Local(l),
-                adjustments,
-                is_ty_unified,
-                moved_before_use,
-            }),
+        if cx.tcx.hir().span(parent_id).ctxt() != ctxt {
+            return ControlFlow::Break(());
+        }
+        if let Node::Expr(e) = parent {
+            match e.kind {
+                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                },
+                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                },
+                ExprKind::Block(..) => moved_before_use = true,
+                _ => {},
+            }
+        }
+        ControlFlow::Continue(())
+    })?
+    .continue_value()
+    .map(|(use_node, child_id)| {
+        let node = match use_node {
+            Node::Local(l) => ExprUseNode::Local(l),
+            Node::ExprField(field) => ExprUseNode::Field(field),
+
             Node::Item(&Item {
                 kind: ItemKind::Static(..) | ItemKind::Const(..),
                 owner_id,
-                span,
                 ..
             })
             | Node::TraitItem(&TraitItem {
                 kind: TraitItemKind::Const(..),
                 owner_id,
-                span,
                 ..
             })
             | Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Const(..),
                 owner_id,
-                span,
                 ..
-            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
-                node: ExprUseNode::ConstStatic(owner_id),
-                adjustments,
-                is_ty_unified,
-                moved_before_use,
-            }),
+            }) => ExprUseNode::ConstStatic(owner_id),
 
             Node::Item(&Item {
                 kind: ItemKind::Fn(..),
                 owner_id,
-                span,
                 ..
             })
             | Node::TraitItem(&TraitItem {
                 kind: TraitItemKind::Fn(..),
                 owner_id,
-                span,
                 ..
             })
             | Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Fn(..),
                 owner_id,
-                span,
                 ..
-            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
-                node: ExprUseNode::Return(owner_id),
-                adjustments,
-                is_ty_unified,
-                moved_before_use,
-            }),
-
-            Node::ExprField(field) if field.span.ctxt() == ctxt => Some(ExprUseCtxt {
-                node: ExprUseNode::Field(field),
-                adjustments,
-                is_ty_unified,
-                moved_before_use,
-            }),
+            }) => ExprUseNode::Return(owner_id),
 
-            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
-                ExprKind::Ret(_) => Some(ExprUseCtxt {
-                    node: ExprUseNode::Return(OwnerId {
-                        def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
-                    }),
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
-                }),
-                ExprKind::Closure(closure) => Some(ExprUseCtxt {
-                    node: ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
-                }),
-                ExprKind::Call(func, args) => Some(ExprUseCtxt {
-                    node: match args.iter().position(|arg| arg.hir_id == child_id) {
-                        Some(i) => ExprUseNode::FnArg(func, i),
-                        None => ExprUseNode::Callee,
-                    },
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
-                }),
-                ExprKind::MethodCall(name, _, args, _) => Some(ExprUseCtxt {
-                    node: ExprUseNode::MethodArg(
-                        parent.hir_id,
-                        name.args,
-                        args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
-                    ),
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
-                }),
-                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(ExprUseCtxt {
-                    node: ExprUseNode::FieldAccess(name),
-                    adjustments,
-                    is_ty_unified,
-                    moved_before_use,
+            Node::Expr(use_expr) => match use_expr.kind {
+                ExprKind::Ret(_) => ExprUseNode::Return(OwnerId {
+                    def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
                 }),
-                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
-                    is_ty_unified = true;
-                    moved_before_use = true;
-                    None
-                },
-                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
-                    is_ty_unified = true;
-                    moved_before_use = true;
-                    None
+                ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
+                ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == child_id) {
+                    Some(i) => ExprUseNode::FnArg(func, i),
+                    None => ExprUseNode::Callee,
                 },
-                ExprKind::Block(..) => {
-                    moved_before_use = true;
-                    None
-                },
-                _ => None,
+                ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg(
+                    use_expr.hir_id,
+                    name.args,
+                    args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
+                ),
+                ExprKind::Field(child, name) if child.hir_id == e.hir_id => ExprUseNode::FieldAccess(name),
+                _ => ExprUseNode::Expr,
             },
-            _ => None,
+            _ => ExprUseNode::Other,
+        };
+        ExprUseCtxt {
+            node,
+            adjustments,
+            is_ty_unified,
+            moved_before_use,
         }
     })
 }
@@ -3270,3 +3203,131 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<
             })
     }
 }
+
+/// Produces a path from a local caller to the type of the called method. Suitable for user
+/// output/suggestions.
+///
+/// Returned path can be either absolute (for methods defined non-locally), or relative (for local
+/// methods).
+pub fn get_path_from_caller_to_method_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    from: LocalDefId,
+    method: DefId,
+    args: GenericArgsRef<'tcx>,
+) -> String {
+    let assoc_item = tcx.associated_item(method);
+    let def_id = assoc_item.container_id(tcx);
+    match assoc_item.container {
+        rustc_ty::TraitContainer => get_path_to_callee(tcx, from, def_id),
+        rustc_ty::ImplContainer => {
+            let ty = tcx.type_of(def_id).instantiate_identity();
+            get_path_to_ty(tcx, from, ty, args)
+        },
+    }
+}
+
+fn get_path_to_ty<'tcx>(tcx: TyCtxt<'tcx>, from: LocalDefId, ty: Ty<'tcx>, args: GenericArgsRef<'tcx>) -> String {
+    match ty.kind() {
+        rustc_ty::Adt(adt, _) => get_path_to_callee(tcx, from, adt.did()),
+        // TODO these types need to be recursively resolved as well
+        rustc_ty::Array(..)
+        | rustc_ty::Dynamic(..)
+        | rustc_ty::Never
+        | rustc_ty::RawPtr(_)
+        | rustc_ty::Ref(..)
+        | rustc_ty::Slice(_)
+        | rustc_ty::Tuple(_) => format!("<{}>", EarlyBinder::bind(ty).instantiate(tcx, args)),
+        _ => ty.to_string(),
+    }
+}
+
+/// Produce a path from some local caller to the callee. Suitable for user output/suggestions.
+fn get_path_to_callee(tcx: TyCtxt<'_>, from: LocalDefId, callee: DefId) -> String {
+    // only search for a relative path if the call is fully local
+    if callee.is_local() {
+        let callee_path = tcx.def_path(callee);
+        let caller_path = tcx.def_path(from.to_def_id());
+        maybe_get_relative_path(&caller_path, &callee_path, 2)
+    } else {
+        tcx.def_path_str(callee)
+    }
+}
+
+/// Tries to produce a relative path from `from` to `to`; if such a path would contain more than
+/// `max_super` `super` items, produces an absolute path instead. Both `from` and `to` should be in
+/// the local crate.
+///
+/// Suitable for user output/suggestions.
+///
+/// This ignores use items, and assumes that the target path is visible from the source
+/// path (which _should_ be a reasonable assumption since we in order to be able to use an object of
+/// certain type T, T is required to be visible).
+///
+/// TODO make use of `use` items. Maybe we should have something more sophisticated like
+/// rust-analyzer does? <https://docs.rs/ra_ap_hir_def/0.0.169/src/ra_ap_hir_def/find_path.rs.html#19-27>
+fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> String {
+    use itertools::EitherOrBoth::{Both, Left, Right};
+
+    // 1. skip the segments common for both paths (regardless of their type)
+    let unique_parts = to
+        .data
+        .iter()
+        .zip_longest(from.data.iter())
+        .skip_while(|el| matches!(el, Both(l, r) if l == r))
+        .map(|el| match el {
+            Both(l, r) => Both(l.data, r.data),
+            Left(l) => Left(l.data),
+            Right(r) => Right(r.data),
+        });
+
+    // 2. for the remaning segments, construct relative path using only mod names and `super`
+    let mut go_up_by = 0;
+    let mut path = Vec::new();
+    for el in unique_parts {
+        match el {
+            Both(l, r) => {
+                // consider:
+                // a::b::sym:: ::    refers to
+                // c::d::e  ::f::sym
+                // result should be super::super::c::d::e::f
+                //
+                // alternatively:
+                // a::b::c  ::d::sym refers to
+                // e::f::sym:: ::
+                // result should be super::super::super::super::e::f
+                if let DefPathData::TypeNs(s) = l {
+                    path.push(s.to_string());
+                }
+                if let DefPathData::TypeNs(_) = r {
+                    go_up_by += 1;
+                }
+            },
+            // consider:
+            // a::b::sym:: ::    refers to
+            // c::d::e  ::f::sym
+            // when looking at `f`
+            Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()),
+            // consider:
+            // a::b::c  ::d::sym refers to
+            // e::f::sym:: ::
+            // when looking at `d`
+            Right(DefPathData::TypeNs(_)) => go_up_by += 1,
+            _ => {},
+        }
+    }
+
+    if go_up_by > max_super {
+        // `super` chain would be too long, just use the absolute path instead
+        once(String::from("crate"))
+            .chain(to.data.iter().filter_map(|el| {
+                if let DefPathData::TypeNs(sym) = el.data {
+                    Some(sym.to_string())
+                } else {
+                    None
+                }
+            }))
+            .join("::")
+    } else {
+        repeat(String::from("super")).take(go_up_by).chain(path).join("::")
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 11bb16ff6c5..6762c883005 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -1000,35 +1000,6 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
     }
 }
 
-/// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
-pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [ty::Clause<'_>]) -> bool {
-    let ty::Param(ty) = *ty.kind() else {
-        return false;
-    };
-    let lang = tcx.lang_items();
-    let (Some(fn_once_id), Some(fn_mut_id), Some(fn_id)) = (lang.fn_once_trait(), lang.fn_mut_trait(), lang.fn_trait())
-    else {
-        return false;
-    };
-    predicates
-        .iter()
-        .try_fold(false, |found, p| {
-            if let ty::ClauseKind::Trait(p) = p.kind().skip_binder()
-                && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
-                && ty.index == self_ty.index
-            {
-                // This should use `super_traits_of`, but that's a private function.
-                if p.trait_ref.def_id == fn_once_id {
-                    return Some(true);
-                } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id {
-                    return None;
-                }
-            }
-            Some(found)
-        })
-        .unwrap_or(false)
-}
-
 /// Comes up with an "at least" guesstimate for the type's size, not taking into
 /// account the layout of type parameters.
 pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {