about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/await_holding_invalid.rs3
-rw-r--r--clippy_lints/src/disallowed_macros.rs5
-rw-r--r--clippy_lints/src/disallowed_methods.rs5
-rw-r--r--clippy_lints/src/disallowed_types.rs40
-rw-r--r--clippy_lints/src/missing_enforced_import_rename.rs2
-rw-r--r--clippy_lints/src/mut_key.rs5
-rw-r--r--clippy_lints/src/utils/conf.rs4
-rw-r--r--clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs4
-rw-r--r--clippy_lints/src/utils/internal_lints/invalid_paths.rs4
-rw-r--r--clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs48
-rw-r--r--clippy_utils/src/lib.rs307
-rw-r--r--tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr4
-rw-r--r--tests/ui-toml/toml_disallowed_methods/clippy.toml6
-rw-r--r--tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs30
-rw-r--r--tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr50
15 files changed, 281 insertions, 236 deletions
diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs
index 34717811866..d40a385435a 100644
--- a/clippy_lints/src/await_holding_invalid.rs
+++ b/clippy_lints/src/await_holding_invalid.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{match_def_path, paths};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def::{Namespace, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -189,7 +188,7 @@ impl LateLintPass<'_> for AwaitHolding {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         for conf in &self.conf_invalid_types {
             let segs: Vec<_> = conf.path().split("::").collect();
-            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
+            for id in clippy_utils::def_path_def_ids(cx, &segs) {
                 self.def_ids.insert(id, conf.clone());
             }
         }
diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs
index 5ab7144e290..68122b4cef5 100644
--- a/clippy_lints/src/disallowed_macros.rs
+++ b/clippy_lints/src/disallowed_macros.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::macro_backtrace;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def::{Namespace, Res};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
 use rustc_lint::{LateContext, LateLintPass};
@@ -89,7 +88,7 @@ impl DisallowedMacros {
                     &format!("use of a disallowed macro `{}`", conf.path()),
                     |diag| {
                         if let Some(reason) = conf.reason() {
-                            diag.note(&format!("{reason} (from clippy.toml)"));
+                            diag.note(reason);
                         }
                     },
                 );
@@ -104,7 +103,7 @@ impl LateLintPass<'_> for DisallowedMacros {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         for (index, conf) in self.conf_disallowed.iter().enumerate() {
             let segs: Vec<_> = conf.path().split("::").collect();
-            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::MacroNS)) {
+            for id in clippy_utils::def_path_def_ids(cx, &segs) {
                 self.disallowed.insert(id, index);
             }
         }
diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs
index 6ac85606d9c..ca8671c8f1a 100644
--- a/clippy_lints/src/disallowed_methods.rs
+++ b/clippy_lints/src/disallowed_methods.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
 
-use rustc_hir::def::{Namespace, Res};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         for (index, conf) in self.conf_disallowed.iter().enumerate() {
             let segs: Vec<_> = conf.path().split("::").collect();
-            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) {
+            for id in clippy_utils::def_path_def_ids(cx, &segs) {
                 self.disallowed.insert(id, index);
             }
         }
@@ -104,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
         let msg = format!("use of a disallowed method `{}`", conf.path());
         span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
             if let Some(reason) = conf.reason() {
-                diag.note(&format!("{reason} (from clippy.toml)"));
+                diag.note(reason);
             }
         });
     }
diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs
index c7131fc164d..aee3d8c4f08 100644
--- a/clippy_lints/src/disallowed_types.rs
+++ b/clippy_lints/src/disallowed_types.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def::{Namespace, Res};
+use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -53,8 +53,8 @@ declare_clippy_lint! {
 #[derive(Clone, Debug)]
 pub struct DisallowedTypes {
     conf_disallowed: Vec<conf::DisallowedPath>,
-    def_ids: FxHashMap<DefId, Option<String>>,
-    prim_tys: FxHashMap<PrimTy, Option<String>>,
+    def_ids: FxHashMap<DefId, usize>,
+    prim_tys: FxHashMap<PrimTy, usize>,
 }
 
 impl DisallowedTypes {
@@ -69,13 +69,13 @@ impl DisallowedTypes {
     fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
         match res {
             Res::Def(_, did) => {
-                if let Some(reason) = self.def_ids.get(did) {
-                    emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
+                if let Some(&index) = self.def_ids.get(did) {
+                    emit(cx, &cx.tcx.def_path_str(*did), span, &self.conf_disallowed[index]);
                 }
             },
             Res::PrimTy(prim) => {
-                if let Some(reason) = self.prim_tys.get(prim) {
-                    emit(cx, prim.name_str(), span, reason.as_deref());
+                if let Some(&index) = self.prim_tys.get(prim) {
+                    emit(cx, prim.name_str(), span, &self.conf_disallowed[index]);
                 }
             },
             _ => {},
@@ -87,17 +87,19 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
-        for conf in &self.conf_disallowed {
+        for (index, conf) in self.conf_disallowed.iter().enumerate() {
             let segs: Vec<_> = conf.path().split("::").collect();
-            let reason = conf.reason().map(|reason| format!("{reason} (from clippy.toml)"));
-            match clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
-                Res::Def(_, id) => {
-                    self.def_ids.insert(id, reason);
-                },
-                Res::PrimTy(ty) => {
-                    self.prim_tys.insert(ty, reason);
-                },
-                _ => {},
+
+            for res in clippy_utils::def_path_res(cx, &segs) {
+                match res {
+                    Res::Def(_, id) => {
+                        self.def_ids.insert(id, index);
+                    },
+                    Res::PrimTy(ty) => {
+                        self.prim_tys.insert(ty, index);
+                    },
+                    _ => {},
+                }
             }
         }
     }
@@ -119,14 +121,14 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
     }
 }
 
-fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
+fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) {
     span_lint_and_then(
         cx,
         DISALLOWED_TYPES,
         span,
         &format!("`{name}` is not allowed according to config"),
         |diag| {
-            if let Some(reason) = reason {
+            if let Some(reason) = conf.reason() {
                 diag.note(reason);
             }
         },
diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs
index 872679f25ab..4712846939e 100644
--- a/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/clippy_lints/src/missing_enforced_import_rename.rs
@@ -59,7 +59,7 @@ impl LateLintPass<'_> for ImportRename {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         for Rename { path, rename } in &self.conf_renames {
             let segs = path.split("::").collect::<Vec<_>>();
-            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) {
+            for id in clippy_utils::def_path_def_ids(cx, &segs) {
                 self.renames.insert(id, Symbol::intern(rename));
             }
         }
diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs
index 551b6ed1227..f0f152904f7 100644
--- a/clippy_lints/src/mut_key.rs
+++ b/clippy_lints/src/mut_key.rs
@@ -1,8 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{def_path_res, trait_ref_of_method};
+use clippy_utils::{def_path_def_ids, trait_ref_of_method};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_hir::def::Namespace;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
@@ -94,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
         let mut path = Vec::new();
         for ty in &self.ignore_interior_mutability {
             path.extend(ty.split("::"));
-            if let Some(id) = def_path_res(cx, &path[..], Some(Namespace::TypeNS)).opt_def_id() {
+            for id in def_path_def_ids(cx, &path[..]) {
                 self.ignore_mut_def_ids.insert(id);
             }
             path.clear();
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 2771c26255a..5bd88fa3c1c 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -53,11 +53,11 @@ impl DisallowedPath {
         path
     }
 
-    pub fn reason(&self) -> Option<&str> {
+    pub fn reason(&self) -> Option<String> {
         match self {
             Self::WithReason {
                 reason: Some(reason), ..
-            } => Some(reason),
+            } => Some(format!("{reason} (from clippy.toml)")),
             _ => None,
         }
     }
diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index 096b601572b..4b33d492a0e 100644
--- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -2,7 +2,7 @@ use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
-use clippy_utils::{def_path_res, is_expn_of, match_def_path, paths};
+use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
         }
 
         for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
-            if let Some(def_id) = def_path_res(cx, module, None).opt_def_id() {
+            for def_id in def_path_def_ids(cx, module) {
                 for item in cx.tcx.module_children(def_id).iter() {
                     if_chain! {
                         if let Res::Def(DefKind::Const, item_def_id) = item.res;
diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 25532dd4e26..4e2e1cc8d77 100644
--- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -3,7 +3,7 @@ use clippy_utils::def_path_res;
 use clippy_utils::diagnostics::span_lint;
 use if_chain::if_chain;
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::DefKind;
 use rustc_hir::Item;
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
 // This is not a complete resolver for paths. It works on all the paths currently used in the paths
 // module.  That's all it does and all it needs to do.
 pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
-    if def_path_res(cx, path, None) != Res::Err {
+    if !def_path_res(cx, path).is_empty() {
         return true;
     }
 
diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index 4cf76f53625..0d91398b74f 100644
--- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -1,19 +1,19 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{def_path_res, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
+use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, Local, Mutability, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc};
-use rustc_middle::ty::{self, AssocKind, DefIdTree, Ty};
+use rustc_middle::ty::{self, DefIdTree, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
 use std::str;
@@ -110,7 +110,7 @@ impl UnnecessaryDefPath {
             // Extract the path to the matched type
             if let Some(segments) = path_to_matched_type(cx, item_arg);
             let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
-            if let Some(def_id) = inherent_def_path_res(cx, &segments[..]);
+            if let Some(def_id) = def_path_def_ids(cx, &segments[..]).next();
             then {
                 // Check if the target item is a diagnostic item or LangItem.
                 #[rustfmt::skip]
@@ -209,7 +209,7 @@ impl UnnecessaryDefPath {
     fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) {
         let Some(path) = path_from_array(elements) else { return };
 
-        if let Some(def_id) = inherent_def_path_res(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
+        for def_id in def_path_def_ids(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
             self.array_def_ids.insert((def_id, span));
         }
     }
@@ -293,41 +293,11 @@ fn path_from_array(exprs: &[Expr<'_>]) -> Option<Vec<String>> {
         .collect()
 }
 
-// def_path_res will match field names before anything else, but for this we want to match
-// inherent functions first.
-fn inherent_def_path_res(cx: &LateContext<'_>, segments: &[&str]) -> Option<DefId> {
-    def_path_res(cx, segments, None).opt_def_id().map(|def_id| {
-        if cx.tcx.def_kind(def_id) == DefKind::Field {
-            let method_name = *segments.last().unwrap();
-            cx.tcx
-                .def_key(def_id)
-                .parent
-                .and_then(|parent_idx| {
-                    cx.tcx
-                        .inherent_impls(DefId {
-                            index: parent_idx,
-                            krate: def_id.krate,
-                        })
-                        .iter()
-                        .find_map(|impl_id| {
-                            cx.tcx.associated_items(*impl_id).find_by_name_and_kind(
-                                cx.tcx,
-                                Ident::from_str(method_name),
-                                AssocKind::Fn,
-                                *impl_id,
-                            )
-                        })
-                })
-                .map_or(def_id, |item| item.def_id)
-        } else {
-            def_id
-        }
-    })
-}
-
 fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> {
     if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) {
-        let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id();
+        let lang_items = def_path_def_ids(cx, &["rustc_hir", "lang_items", "LangItem"])
+            .next()
+            .unwrap();
         let item_name = cx
             .tcx
             .adt_def(lang_items)
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index f7d3c91777e..0e72075e9f4 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -80,17 +80,16 @@ use rustc_ast::ast::{self, LitKind};
 use rustc_ast::Attribute;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unhash::UnhashMap;
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
-    def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination, Expr,
-    ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
-    Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
-    TraitRef, TyKind, UnOp,
+    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination,
+    Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
+    MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
+    TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -112,7 +111,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::source_map::SourceMap;
 use rustc_span::sym;
-use rustc_span::symbol::{kw, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::Integer;
 
@@ -525,165 +524,177 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
     path_res(cx, maybe_path).opt_def_id()
 }
 
-fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
-    let single = |ty| tcx.incoherent_impls(ty).iter().copied();
-    let empty = || [].iter().copied();
-    match name {
-        "bool" => single(BoolSimplifiedType),
-        "char" => single(CharSimplifiedType),
-        "str" => single(StrSimplifiedType),
-        "array" => single(ArraySimplifiedType),
-        "slice" => single(SliceSimplifiedType),
+fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
+    let ty = match name {
+        "bool" => BoolSimplifiedType,
+        "char" => CharSimplifiedType,
+        "str" => StrSimplifiedType,
+        "array" => ArraySimplifiedType,
+        "slice" => SliceSimplifiedType,
         // FIXME: rustdoc documents these two using just `pointer`.
         //
         // Maybe this is something we should do here too.
-        "const_ptr" => single(PtrSimplifiedType(Mutability::Not)),
-        "mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)),
-        "isize" => single(IntSimplifiedType(IntTy::Isize)),
-        "i8" => single(IntSimplifiedType(IntTy::I8)),
-        "i16" => single(IntSimplifiedType(IntTy::I16)),
-        "i32" => single(IntSimplifiedType(IntTy::I32)),
-        "i64" => single(IntSimplifiedType(IntTy::I64)),
-        "i128" => single(IntSimplifiedType(IntTy::I128)),
-        "usize" => single(UintSimplifiedType(UintTy::Usize)),
-        "u8" => single(UintSimplifiedType(UintTy::U8)),
-        "u16" => single(UintSimplifiedType(UintTy::U16)),
-        "u32" => single(UintSimplifiedType(UintTy::U32)),
-        "u64" => single(UintSimplifiedType(UintTy::U64)),
-        "u128" => single(UintSimplifiedType(UintTy::U128)),
-        "f32" => single(FloatSimplifiedType(FloatTy::F32)),
-        "f64" => single(FloatSimplifiedType(FloatTy::F64)),
-        _ => empty(),
-    }
-}
-
-/// Resolves a def path like `std::vec::Vec`. `namespace_hint` can be supplied to disambiguate
-/// between `std::vec` the module and `std::vec` the macro
-///
-/// This function is expensive and should be used sparingly.
-pub fn def_path_res(cx: &LateContext<'_>, path: &[&str], namespace_hint: Option<Namespace>) -> Res {
-    fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str, matches_ns: impl Fn(Res) -> bool) -> Option<Res> {
-        match tcx.def_kind(def_id) {
-            DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
-                .module_children(def_id)
-                .iter()
-                .find(|item| item.ident.name.as_str() == name && matches_ns(item.res.expect_non_local()))
-                .map(|child| child.res.expect_non_local()),
-            DefKind::Impl => tcx
-                .associated_item_def_ids(def_id)
-                .iter()
-                .copied()
-                .find(|assoc_def_id| tcx.item_name(*assoc_def_id).as_str() == name)
-                .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)),
-            DefKind::Struct | DefKind::Union => tcx
-                .adt_def(def_id)
-                .non_enum_variant()
-                .fields
-                .iter()
-                .find(|f| f.name.as_str() == name)
-                .map(|f| Res::Def(DefKind::Field, f.did)),
-            _ => None,
+        "const_ptr" => PtrSimplifiedType(Mutability::Not),
+        "mut_ptr" => PtrSimplifiedType(Mutability::Mut),
+        "isize" => IntSimplifiedType(IntTy::Isize),
+        "i8" => IntSimplifiedType(IntTy::I8),
+        "i16" => IntSimplifiedType(IntTy::I16),
+        "i32" => IntSimplifiedType(IntTy::I32),
+        "i64" => IntSimplifiedType(IntTy::I64),
+        "i128" => IntSimplifiedType(IntTy::I128),
+        "usize" => UintSimplifiedType(UintTy::Usize),
+        "u8" => UintSimplifiedType(UintTy::U8),
+        "u16" => UintSimplifiedType(UintTy::U16),
+        "u32" => UintSimplifiedType(UintTy::U32),
+        "u64" => UintSimplifiedType(UintTy::U64),
+        "u128" => UintSimplifiedType(UintTy::U128),
+        "f32" => FloatSimplifiedType(FloatTy::F32),
+        "f64" => FloatSimplifiedType(FloatTy::F64),
+        _ => return [].iter().copied(),
+    };
+
+    tcx.incoherent_impls(ty).iter().copied()
+}
+
+fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
+    match tcx.def_kind(def_id) {
+        DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
+            .module_children(def_id)
+            .iter()
+            .filter(|item| item.ident.name == name)
+            .map(|child| child.res.expect_non_local())
+            .collect(),
+        DefKind::Impl => tcx
+            .associated_item_def_ids(def_id)
+            .iter()
+            .copied()
+            .filter(|assoc_def_id| tcx.item_name(*assoc_def_id) == name)
+            .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id))
+            .collect(),
+        _ => Vec::new(),
+    }
+}
+
+fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res> {
+    let hir = tcx.hir();
+
+    let root_mod;
+    let item_kind = match hir.find_by_def_id(local_id) {
+        Some(Node::Crate(r#mod)) => {
+            root_mod = ItemKind::Mod(r#mod);
+            &root_mod
+        },
+        Some(Node::Item(item)) => &item.kind,
+        _ => return Vec::new(),
+    };
+
+    let res = |ident: Ident, owner_id: OwnerId| {
+        if ident.name == name {
+            let def_id = owner_id.to_def_id();
+            Some(Res::Def(tcx.def_kind(def_id), def_id))
+        } else {
+            None
         }
+    };
+
+    match item_kind {
+        ItemKind::Mod(r#mod) => r#mod
+            .item_ids
+            .iter()
+            .filter_map(|&item_id| res(hir.item(item_id).ident, item_id.def_id))
+            .collect(),
+        ItemKind::Impl(r#impl) => r#impl
+            .items
+            .iter()
+            .filter_map(|&ImplItemRef { ident, id, .. }| res(ident, id.def_id))
+            .collect(),
+        ItemKind::Trait(.., trait_item_refs) => trait_item_refs
+            .iter()
+            .filter_map(|&TraitItemRef { ident, id, .. }| res(ident, id.def_id))
+            .collect(),
+        _ => Vec::new(),
+    }
+}
+
+fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
+    if let Some(local_id) = def_id.as_local() {
+        local_item_children_by_name(tcx, local_id, name)
+    } else {
+        non_local_item_children_by_name(tcx, def_id, name)
     }
+}
 
-    fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
+/// Resolves a def path like `std::vec::Vec`.
+///
+/// Can return multiple resolutions when there are multiple versions of the same crate, e.g.
+/// `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0.
+///
+/// Also returns multiple results when there are mulitple paths under the same name e.g. `std::vec`
+/// would have both a [`DefKind::Mod`] and [`DefKind::Macro`].
+///
+/// This function is expensive and should be used sparingly.
+pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res> {
+    fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator<Item = DefId> + '_ {
         tcx.crates(())
             .iter()
             .copied()
-            .find(|&num| tcx.crate_name(num).as_str() == name)
+            .filter(move |&num| tcx.crate_name(num) == name)
             .map(CrateNum::as_def_id)
     }
 
-    let (base, path) = match *path {
+    let tcx = cx.tcx;
+
+    let (base, mut path) = match *path {
         [primitive] => {
-            return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
-        },
-        [base, ref path @ ..] => {
-            let crate_name = cx.sess().opts.crate_name.as_deref();
-            if Some(base) == crate_name {
-                return def_path_res_local(cx, path);
-            }
-            (base, path)
+            return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)];
         },
-        _ => return Res::Err,
+        [base, ref path @ ..] => (base, path),
+        _ => return Vec::new(),
     };
-    let tcx = cx.tcx;
-    let starts = find_primitive(tcx, base)
-        .chain(find_crate(tcx, base))
+
+    let base_sym = Symbol::intern(base);
+
+    let local_crate = if tcx.crate_name(LOCAL_CRATE) == base_sym {
+        Some(LOCAL_CRATE.as_def_id())
+    } else {
+        None
+    };
+
+    let starts = find_primitive_impls(tcx, base)
+        .chain(find_crates(tcx, base_sym))
+        .chain(local_crate)
         .map(|id| Res::Def(tcx.def_kind(id), id));
 
-    for first in starts {
-        let last = path
-            .iter()
-            .copied()
-            .enumerate()
-            // for each segment, find the child item
-            .try_fold(first, |res, (idx, segment)| {
-                let matches_ns = |res: Res| {
-                    // If at the last segment in the path, respect the namespace hint
-                    if idx == path.len() - 1 {
-                        match namespace_hint {
-                            Some(ns) => res.matches_ns(ns),
-                            None => true,
-                        }
-                    } else {
-                        res.matches_ns(Namespace::TypeNS)
-                    }
-                };
-
-                let def_id = res.def_id();
-                if let Some(item) = item_child_by_name(tcx, def_id, segment, matches_ns) {
-                    Some(item)
-                } else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
-                    // it is not a child item so check inherent impl items
-                    tcx.inherent_impls(def_id)
-                        .iter()
-                        .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment, matches_ns))
-                } else {
-                    None
-                }
-            });
+    let mut resolutions: Vec<Res> = starts.collect();
 
-        if let Some(last) = last {
-            return last;
-        }
+    while let [segment, rest @ ..] = path {
+        path = rest;
+        let segment = Symbol::intern(segment);
+
+        resolutions = resolutions
+            .into_iter()
+            .filter_map(|res| res.opt_def_id())
+            .flat_map(|def_id| {
+                // When the current def_id is e.g. `struct S`, check the impl items in
+                // `impl S { ... }`
+                let inherent_impl_children = tcx
+                    .inherent_impls(def_id)
+                    .iter()
+                    .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
+
+                let direct_children = item_children_by_name(tcx, def_id, segment);
+
+                inherent_impl_children.chain(direct_children)
+            })
+            .collect();
     }
-    Res::Err
+
+    resolutions
 }
 
-fn def_path_res_local(cx: &LateContext<'_>, mut path: &[&str]) -> Res {
-    let map = cx.tcx.hir();
-    let mut ids = map.root_module().item_ids;
-    while let Some(&segment) = path.first() {
-        let mut next_ids = None;
-        for i in ids {
-            if let Some(Node::Item(hir::Item {
-                ident,
-                kind,
-                def_id: item_def_id,
-                ..
-            })) = map.find(i.hir_id())
-            {
-                if ident.name.as_str() == segment {
-                    path = &path[1..];
-                    if path.is_empty() {
-                        let def_id = item_def_id.to_def_id();
-                        return Res::Def(cx.tcx.def_kind(def_id), def_id);
-                    }
-                    if let ItemKind::Mod(m) = kind {
-                        next_ids = Some(m.item_ids);
-                    };
-                    break;
-                }
-            }
-        }
-        if let Some(next_ids) = next_ids {
-            ids = next_ids;
-        } else {
-            break;
-        }
-    }
-    Res::Err
+/// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`].
+pub fn def_path_def_ids(cx: &LateContext<'_>, path: &[&str]) -> impl Iterator<Item = DefId> {
+    def_path_res(cx, path).into_iter().filter_map(|res| res.opt_def_id())
 }
 
 /// Convenience function to get the `DefId` of a trait by path.
@@ -691,10 +702,10 @@ fn def_path_res_local(cx: &LateContext<'_>, mut path: &[&str]) -> Res {
 ///
 /// This function is expensive and should be used sparingly.
 pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
-    match def_path_res(cx, path, Some(Namespace::TypeNS)) {
+    def_path_res(cx, path).into_iter().find_map(|res| match res {
         Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
         _ => None,
-    }
+    })
 }
 
 /// Gets the `hir::TraitRef` of the trait the given method is implemented for.
diff --git a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
index 4c75998437f..825aa1487e7 100644
--- a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
+++ b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
@@ -4,7 +4,7 @@ error: `std::string::String` may not be held across an `await` point per `clippy
 LL |     let _x = String::from("hello");
    |         ^^
    |
-   = note: strings are bad
+   = note: strings are bad (from clippy.toml)
    = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings`
 
 error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml`
@@ -19,7 +19,7 @@ error: `std::string::String` may not be held across an `await` point per `clippy
 LL |         let _x = String::from("hi!");
    |             ^^
    |
-   = note: strings are bad
+   = note: strings are bad (from clippy.toml)
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui-toml/toml_disallowed_methods/clippy.toml b/tests/ui-toml/toml_disallowed_methods/clippy.toml
index 28774db625b..41dbd506847 100644
--- a/tests/ui-toml/toml_disallowed_methods/clippy.toml
+++ b/tests/ui-toml/toml_disallowed_methods/clippy.toml
@@ -8,4 +8,10 @@ disallowed-methods = [
     { path = "regex::Regex::is_match", reason = "no matching allowed" },
     # can use an inline table but omit reason
     { path = "regex::Regex::new" },
+    # local paths
+    "conf_disallowed_methods::local_fn",
+    "conf_disallowed_methods::local_mod::f",
+    "conf_disallowed_methods::Struct::method",
+    "conf_disallowed_methods::Trait::provided_method",
+    "conf_disallowed_methods::Trait::implemented_method",
 ]
diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
index b483f160028..2f3160c8338 100644
--- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
+++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
@@ -1,3 +1,5 @@
+// compile-flags: --crate-name conf_disallowed_methods
+
 #![warn(clippy::disallowed_methods)]
 
 extern crate futures;
@@ -6,6 +8,27 @@ extern crate regex;
 use futures::stream::{empty, select_all};
 use regex::Regex;
 
+fn local_fn() {}
+
+struct Struct;
+
+impl Struct {
+    fn method(&self) {}
+}
+
+trait Trait {
+    fn provided_method(&self) {}
+    fn implemented_method(&self);
+}
+
+impl Trait for Struct {
+    fn implemented_method(&self) {}
+}
+
+mod local_mod {
+    pub fn f() {}
+}
+
 fn main() {
     let re = Regex::new(r"ab.*c").unwrap();
     re.is_match("abc");
@@ -26,4 +49,11 @@ fn main() {
 
     // resolve ambiguity between `futures::stream::select_all` the module and the function
     let same_name_as_module = select_all(vec![empty::<()>()]);
+
+    local_fn();
+    local_mod::f();
+    let s = Struct;
+    s.method();
+    s.provided_method();
+    s.implemented_method();
 }
diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index 6d78c32e127..148d1cae51f 100644
--- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
+++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -1,5 +1,5 @@
 error: use of a disallowed method `regex::Regex::new`
-  --> $DIR/conf_disallowed_methods.rs:10:14
+  --> $DIR/conf_disallowed_methods.rs:33:14
    |
 LL |     let re = Regex::new(r"ab.*c").unwrap();
    |              ^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     let re = Regex::new(r"ab.*c").unwrap();
    = note: `-D clippy::disallowed-methods` implied by `-D warnings`
 
 error: use of a disallowed method `regex::Regex::is_match`
-  --> $DIR/conf_disallowed_methods.rs:11:5
+  --> $DIR/conf_disallowed_methods.rs:34:5
    |
 LL |     re.is_match("abc");
    |     ^^^^^^^^^^^^^^^^^^
@@ -15,46 +15,76 @@ LL |     re.is_match("abc");
    = note: no matching allowed (from clippy.toml)
 
 error: use of a disallowed method `std::iter::Iterator::sum`
-  --> $DIR/conf_disallowed_methods.rs:14:5
+  --> $DIR/conf_disallowed_methods.rs:37:5
    |
 LL |     a.iter().sum::<i32>();
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `slice::sort_unstable`
-  --> $DIR/conf_disallowed_methods.rs:16:5
+  --> $DIR/conf_disallowed_methods.rs:39:5
    |
 LL |     a.sort_unstable();
    |     ^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> $DIR/conf_disallowed_methods.rs:18:13
+  --> $DIR/conf_disallowed_methods.rs:41:13
    |
 LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> $DIR/conf_disallowed_methods.rs:21:61
+  --> $DIR/conf_disallowed_methods.rs:44:61
    |
 LL |     let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new;
    |                                                             ^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> $DIR/conf_disallowed_methods.rs:24:28
+  --> $DIR/conf_disallowed_methods.rs:47:28
    |
 LL |     let in_call = Box::new(f32::clamp);
    |                            ^^^^^^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> $DIR/conf_disallowed_methods.rs:25:53
+  --> $DIR/conf_disallowed_methods.rs:48:53
    |
 LL |     let in_method_call = ["^", "$"].into_iter().map(Regex::new);
    |                                                     ^^^^^^^^^^
 
 error: use of a disallowed method `futures::stream::select_all`
-  --> $DIR/conf_disallowed_methods.rs:28:31
+  --> $DIR/conf_disallowed_methods.rs:51:31
    |
 LL |     let same_name_as_module = select_all(vec![empty::<()>()]);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 9 previous errors
+error: use of a disallowed method `conf_disallowed_methods::local_fn`
+  --> $DIR/conf_disallowed_methods.rs:53:5
+   |
+LL |     local_fn();
+   |     ^^^^^^^^^^
+
+error: use of a disallowed method `conf_disallowed_methods::local_mod::f`
+  --> $DIR/conf_disallowed_methods.rs:54:5
+   |
+LL |     local_mod::f();
+   |     ^^^^^^^^^^^^^^
+
+error: use of a disallowed method `conf_disallowed_methods::Struct::method`
+  --> $DIR/conf_disallowed_methods.rs:56:5
+   |
+LL |     s.method();
+   |     ^^^^^^^^^^
+
+error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method`
+  --> $DIR/conf_disallowed_methods.rs:57:5
+   |
+LL |     s.provided_method();
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method`
+  --> $DIR/conf_disallowed_methods.rs:58:5
+   |
+LL |     s.implemented_method();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors