about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Macleod <alex@macleod.io>2022-10-05 13:44:01 +0000
committerAlex Macleod <alex@macleod.io>2022-10-05 13:44:06 +0000
commit86c86c37429e95aee45846262bb50239a69be546 (patch)
tree8cb0c81c1608eb25296f6d7862ccdab93f4e3fd5
parent425e1ea73d1e67c38c1d12e160d5fd20b64ffa5d (diff)
downloadrust-86c86c37429e95aee45846262bb50239a69be546.tar.gz
rust-86c86c37429e95aee45846262bb50239a69be546.zip
Add `disallowed_macros` lint
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/await_holding_invalid.rs34
-rw-r--r--clippy_lints/src/disallowed_macros.rs151
-rw-r--r--clippy_lints/src/disallowed_methods.rs15
-rw-r--r--clippy_lints/src/disallowed_types.rs20
-rw-r--r--clippy_lints/src/lib.register_all.rs1
-rw-r--r--clippy_lints/src/lib.register_lints.rs1
-rw-r--r--clippy_lints/src/lib.register_style.rs1
-rw-r--r--clippy_lints/src/lib.rs3
-rw-r--r--clippy_lints/src/missing_enforced_import_rename.rs3
-rw-r--r--clippy_lints/src/utils/conf.rs30
-rw-r--r--clippy_lints/src/utils/internal_lints.rs10
-rw-r--r--clippy_utils/src/lib.rs105
-rw-r--r--src/docs.rs1
-rw-r--r--src/docs/disallowed_macros.txt36
-rw-r--r--tests/ui-toml/disallowed_macros/auxiliary/macros.rs32
-rw-r--r--tests/ui-toml/disallowed_macros/clippy.toml11
-rw-r--r--tests/ui-toml/disallowed_macros/disallowed_macros.rs39
-rw-r--r--tests/ui-toml/disallowed_macros/disallowed_macros.stderr84
-rw-r--r--tests/ui-toml/toml_disallowed_methods/clippy.toml1
-rw-r--r--tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs6
-rw-r--r--tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr24
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr1
23 files changed, 500 insertions, 110 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bfeb009727b..42615179f70 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3820,6 +3820,7 @@ Released 2018-09-13
 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
+[`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros
 [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
 [`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names
diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs
index 24a3588ecf1..34717811866 100644
--- a/clippy_lints/src/await_holding_invalid.rs
+++ b/clippy_lints/src/await_holding_invalid.rs
@@ -1,14 +1,15 @@
 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::{def::Res, AsyncGeneratorKind, Body, BodyId, GeneratorKind};
+use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::GeneratorInteriorTypeCause;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Span};
 
-use crate::utils::conf::DisallowedType;
+use crate::utils::conf::DisallowedPath;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -171,12 +172,12 @@ impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF,
 
 #[derive(Debug)]
 pub struct AwaitHolding {
-    conf_invalid_types: Vec<DisallowedType>,
-    def_ids: FxHashMap<DefId, DisallowedType>,
+    conf_invalid_types: Vec<DisallowedPath>,
+    def_ids: FxHashMap<DefId, DisallowedPath>,
 }
 
 impl AwaitHolding {
-    pub(crate) fn new(conf_invalid_types: Vec<DisallowedType>) -> Self {
+    pub(crate) fn new(conf_invalid_types: Vec<DisallowedPath>) -> Self {
         Self {
             conf_invalid_types,
             def_ids: FxHashMap::default(),
@@ -187,11 +188,8 @@ impl AwaitHolding {
 impl LateLintPass<'_> for AwaitHolding {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         for conf in &self.conf_invalid_types {
-            let path = match conf {
-                DisallowedType::Simple(path) | DisallowedType::WithReason { path, .. } => path,
-            };
-            let segs: Vec<_> = path.split("::").collect();
-            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
+            let segs: Vec<_> = conf.path().split("::").collect();
+            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
                 self.def_ids.insert(id, conf.clone());
             }
         }
@@ -256,20 +254,18 @@ impl AwaitHolding {
     }
 }
 
-fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedType) {
-    let (type_name, reason) = match disallowed {
-        DisallowedType::Simple(path) => (path, &None),
-        DisallowedType::WithReason { path, reason } => (path, reason),
-    };
-
+fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) {
     span_lint_and_then(
         cx,
         AWAIT_HOLDING_INVALID_TYPE,
         span,
-        &format!("`{type_name}` may not be held across an `await` point per `clippy.toml`",),
+        &format!(
+            "`{}` may not be held across an `await` point per `clippy.toml`",
+            disallowed.path()
+        ),
         |diag| {
-            if let Some(reason) = reason {
-                diag.note(reason.clone());
+            if let Some(reason) = disallowed.reason() {
+                diag.note(reason);
             }
         },
     );
diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs
new file mode 100644
index 00000000000..5ab7144e290
--- /dev/null
+++ b/clippy_lints/src/disallowed_macros.rs
@@ -0,0 +1,151 @@
+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};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{ExpnId, Span};
+
+use crate::utils::conf;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Denies the configured macros in clippy.toml
+    ///
+    /// Note: Even though this lint is warn-by-default, it will only trigger if
+    /// macros are defined in the clippy.toml file.
+    ///
+    /// ### Why is this bad?
+    /// Some macros are undesirable in certain contexts, and it's beneficial to
+    /// lint for them as needed.
+    ///
+    /// ### Example
+    /// An example clippy.toml configuration:
+    /// ```toml
+    /// # clippy.toml
+    /// disallowed-macros = [
+    ///     # Can use a string as the path of the disallowed macro.
+    ///     "std::print",
+    ///     # Can also use an inline table with a `path` key.
+    ///     { path = "std::println" },
+    ///     # When using an inline table, can add a `reason` for why the macro
+    ///     # is disallowed.
+    ///     { path = "serde::Serialize", reason = "no serializing" },
+    /// ]
+    /// ```
+    /// ```
+    /// use serde::Serialize;
+    ///
+    /// // Example code where clippy issues a warning
+    /// println!("warns");
+    ///
+    /// // The diagnostic will contain the message "no serializing"
+    /// #[derive(Serialize)]
+    /// struct Data {
+    ///     name: String,
+    ///     value: usize,
+    /// }
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub DISALLOWED_MACROS,
+    style,
+    "use of a disallowed macro"
+}
+
+pub struct DisallowedMacros {
+    conf_disallowed: Vec<conf::DisallowedPath>,
+    disallowed: DefIdMap<usize>,
+    seen: FxHashSet<ExpnId>,
+}
+
+impl DisallowedMacros {
+    pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
+        Self {
+            conf_disallowed,
+            disallowed: DefIdMap::default(),
+            seen: FxHashSet::default(),
+        }
+    }
+
+    fn check(&mut self, cx: &LateContext<'_>, span: Span) {
+        if self.conf_disallowed.is_empty() {
+            return;
+        }
+
+        for mac in macro_backtrace(span) {
+            if !self.seen.insert(mac.expn) {
+                return;
+            }
+
+            if let Some(&index) = self.disallowed.get(&mac.def_id) {
+                let conf = &self.conf_disallowed[index];
+
+                span_lint_and_then(
+                    cx,
+                    DISALLOWED_MACROS,
+                    mac.span,
+                    &format!("use of a disallowed macro `{}`", conf.path()),
+                    |diag| {
+                        if let Some(reason) = conf.reason() {
+                            diag.note(&format!("{reason} (from clippy.toml)"));
+                        }
+                    },
+                );
+            }
+        }
+    }
+}
+
+impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]);
+
+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)) {
+                self.disallowed.insert(id, index);
+            }
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        self.check(cx, expr.span);
+    }
+
+    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
+        self.check(cx, stmt.span);
+    }
+
+    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) {
+        self.check(cx, ty.span);
+    }
+
+    fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
+        self.check(cx, pat.span);
+    }
+
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        self.check(cx, item.span);
+        self.check(cx, item.vis_span);
+    }
+
+    fn check_foreign_item(&mut self, cx: &LateContext<'_>, item: &ForeignItem<'_>) {
+        self.check(cx, item.span);
+        self.check(cx, item.vis_span);
+    }
+
+    fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) {
+        self.check(cx, item.span);
+        self.check(cx, item.vis_span);
+    }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
+        self.check(cx, item.span);
+    }
+
+    fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) {
+        self.check(cx, path.span);
+    }
+}
diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs
index b02f87c07db..1a381f92c03 100644
--- a/clippy_lints/src/disallowed_methods.rs
+++ b/clippy_lints/src/disallowed_methods.rs
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
 
-use rustc_hir::{def::Res, def_id::DefIdMap, Expr, ExprKind};
+use rustc_hir::def::{Namespace, Res};
+use rustc_hir::def_id::DefIdMap;
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
@@ -58,12 +60,12 @@ declare_clippy_lint! {
 
 #[derive(Clone, Debug)]
 pub struct DisallowedMethods {
-    conf_disallowed: Vec<conf::DisallowedMethod>,
+    conf_disallowed: Vec<conf::DisallowedPath>,
     disallowed: DefIdMap<usize>,
 }
 
 impl DisallowedMethods {
-    pub fn new(conf_disallowed: Vec<conf::DisallowedMethod>) -> Self {
+    pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
         Self {
             conf_disallowed,
             disallowed: DefIdMap::default(),
@@ -77,7 +79,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) {
+            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) {
                 self.disallowed.insert(id, index);
             }
         }
@@ -102,10 +104,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 conf::DisallowedMethod::WithReason {
-                reason: Some(reason), ..
-            } = conf
-            {
+            if let Some(reason) = conf.reason() {
                 diag.note(&format!("{reason} (from clippy.toml)"));
             }
         });
diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs
index debcd75ae75..c7131fc164d 100644
--- a/clippy_lints/src/disallowed_types.rs
+++ b/clippy_lints/src/disallowed_types.rs
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
+use rustc_hir::def::{Namespace, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
@@ -50,13 +52,13 @@ declare_clippy_lint! {
 }
 #[derive(Clone, Debug)]
 pub struct DisallowedTypes {
-    conf_disallowed: Vec<conf::DisallowedType>,
+    conf_disallowed: Vec<conf::DisallowedPath>,
     def_ids: FxHashMap<DefId, Option<String>>,
     prim_tys: FxHashMap<PrimTy, Option<String>>,
 }
 
 impl DisallowedTypes {
-    pub fn new(conf_disallowed: Vec<conf::DisallowedType>) -> Self {
+    pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
         Self {
             conf_disallowed,
             def_ids: FxHashMap::default(),
@@ -86,15 +88,9 @@ 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 {
-            let (path, reason) = match conf {
-                conf::DisallowedType::Simple(path) => (path, None),
-                conf::DisallowedType::WithReason { path, reason } => (
-                    path,
-                    reason.as_ref().map(|reason| format!("{reason} (from clippy.toml)")),
-                ),
-            };
-            let segs: Vec<_> = path.split("::").collect();
-            match clippy_utils::def_path_res(cx, &segs) {
+            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);
                 },
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 642d7070fb6..5d26e4b3360 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -45,6 +45,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(derivable_impls::DERIVABLE_IMPLS),
     LintId::of(derive::DERIVE_HASH_XOR_EQ),
     LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
+    LintId::of(disallowed_macros::DISALLOWED_MACROS),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
     LintId::of(disallowed_names::DISALLOWED_NAMES),
     LintId::of(disallowed_types::DISALLOWED_TYPES),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 08eb6c2b39b..05d927dbea7 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -114,6 +114,7 @@ store.register_lints(&[
     derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ,
     derive::EXPL_IMPL_CLONE_ON_COPY,
     derive::UNSAFE_DERIVE_DESERIALIZE,
+    disallowed_macros::DISALLOWED_MACROS,
     disallowed_methods::DISALLOWED_METHODS,
     disallowed_names::DISALLOWED_NAMES,
     disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index 6d5483bc701..8e1390167dc 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -15,6 +15,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
     LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
     LintId::of(dereference::NEEDLESS_BORROW),
+    LintId::of(disallowed_macros::DISALLOWED_MACROS),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
     LintId::of(disallowed_names::DISALLOWED_NAMES),
     LintId::of(disallowed_types::DISALLOWED_TYPES),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index e5d26ac22a7..2dcefd78763 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -199,6 +199,7 @@ mod default_union_representation;
 mod dereference;
 mod derivable_impls;
 mod derive;
+mod disallowed_macros;
 mod disallowed_methods;
 mod disallowed_names;
 mod disallowed_script_idents;
@@ -820,6 +821,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
     store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
     store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
+    let disallowed_macros = conf.disallowed_macros.clone();
+    store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone())));
     let disallowed_methods = conf.disallowed_methods.clone();
     store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs
index 697e6fd24dd..872679f25ab 100644
--- a/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/clippy_lints/src/missing_enforced_import_rename.rs
@@ -58,7 +58,8 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]);
 impl LateLintPass<'_> for ImportRename {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         for Rename { path, rename } in &self.conf_renames {
-            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &path.split("::").collect::<Vec<_>>()) {
+            let segs = path.split("::").collect::<Vec<_>>();
+            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) {
                 self.renames.insert(id, Symbol::intern(rename));
             }
         }
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 2b336e87ef7..668123e4d6e 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -39,28 +39,28 @@ pub struct Rename {
     pub rename: String,
 }
 
-/// A single disallowed method, used by the `DISALLOWED_METHODS` lint.
 #[derive(Clone, Debug, Deserialize)]
 #[serde(untagged)]
-pub enum DisallowedMethod {
+pub enum DisallowedPath {
     Simple(String),
     WithReason { path: String, reason: Option<String> },
 }
 
-impl DisallowedMethod {
+impl DisallowedPath {
     pub fn path(&self) -> &str {
         let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
 
         path
     }
-}
 
-/// A single disallowed type, used by the `DISALLOWED_TYPES` lint.
-#[derive(Clone, Debug, Deserialize)]
-#[serde(untagged)]
-pub enum DisallowedType {
-    Simple(String),
-    WithReason { path: String, reason: Option<String> },
+    pub fn reason(&self) -> Option<&str> {
+        match self {
+            Self::WithReason {
+                reason: Some(reason), ..
+            } => Some(reason),
+            _ => None,
+        }
+    }
 }
 
 /// Conf with parse errors
@@ -315,14 +315,18 @@ define_Conf! {
     ///
     /// Whether to allow certain wildcard imports (prelude, super in tests).
     (warn_on_all_wildcard_imports: bool = false),
+    /// Lint: DISALLOWED_MACROS.
+    ///
+    /// The list of disallowed macros, written as fully qualified paths.
+    (disallowed_macros: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
     /// Lint: DISALLOWED_METHODS.
     ///
     /// The list of disallowed methods, written as fully qualified paths.
-    (disallowed_methods: Vec<crate::utils::conf::DisallowedMethod> = Vec::new()),
+    (disallowed_methods: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
     /// Lint: DISALLOWED_TYPES.
     ///
     /// The list of disallowed types, written as fully qualified paths.
-    (disallowed_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
+    (disallowed_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
     /// Lint: UNREADABLE_LITERAL.
     ///
     /// Should the fraction of a decimal be linted to include separators.
@@ -362,7 +366,7 @@ define_Conf! {
     /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
     (max_suggested_slice_pattern_length: u64 = 3),
     /// Lint: AWAIT_HOLDING_INVALID_TYPE
-    (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
+    (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
     /// Lint: LARGE_INCLUDE_FILE.
     ///
     /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 6309a04c73d..85bcbc7ad23 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -15,7 +15,7 @@ use rustc_ast::visit::FnKind;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{DefKind, Namespace, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::Visitor;
@@ -920,7 +920,7 @@ impl<'tcx> LateLintPass<'tcx> for 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) = def_path_res(cx, &segments[..]).opt_def_id();
+            if let Some(def_id) = def_path_res(cx, &segments[..], None).opt_def_id();
             then {
                 // def_path_res will match field names before anything else, but for this we want to match
                 // inherent functions first.
@@ -952,7 +952,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath {
                         Item::DiagnosticItem(*item_name),
                     )
                 } else 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"]).def_id();
+                    let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id();
                     let item_name = cx.tcx.adt_def(lang_items).variants().iter().nth(lang_item).unwrap().name;
                     (
                         "use of a def path to a `LangItem`",
@@ -1115,7 +1115,7 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation
 // 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) != Res::Err {
+    if def_path_res(cx, path, None) != Res::Err {
         return true;
     }
 
@@ -1206,7 +1206,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).opt_def_id() {
+            if let Some(def_id) = def_path_res(cx, module, None).opt_def_id() {
                 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_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 3caa6380e09..39198519329 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -78,7 +78,7 @@ 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, Res};
+use rustc_hir::def::{DefKind, Namespace, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
@@ -522,15 +522,49 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
     path_res(cx, maybe_path).opt_def_id()
 }
 
-/// Resolves a def path like `std::vec::Vec`.
+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),
+        // 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]) -> Res {
-    fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Option<Res> {
+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)
+                .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)
@@ -548,37 +582,7 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
             _ => None,
         }
     }
-    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),
-            // 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(),
-        }
-    }
+
     fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
         tcx.crates(())
             .iter()
@@ -587,32 +591,45 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
             .map(CrateNum::as_def_id)
     }
 
-    let (base, first, path) = match *path {
-        [base, first, ref path @ ..] => (base, first, path),
+    let (base, path) = match *path {
         [primitive] => {
             return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
         },
+        [base, ref path @ ..] => (base, path),
         _ => return Res::Err,
     };
     let tcx = cx.tcx;
     let starts = find_primitive(tcx, base)
         .chain(find_crate(tcx, base))
-        .filter_map(|id| item_child_by_name(tcx, id, first));
+        .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, segment| {
+            .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) {
+                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))
+                        .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment, matches_ns))
                 } else {
                     None
                 }
@@ -628,8 +645,10 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
 
 /// Convenience function to get the `DefId` of a trait by path.
 /// It could be a trait or trait alias.
+///
+/// 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) {
+    match def_path_res(cx, path, Some(Namespace::TypeNS)) {
         Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
         _ => None,
     }
diff --git a/src/docs.rs b/src/docs.rs
index 1b727e1a100..3bf488ab477 100644
--- a/src/docs.rs
+++ b/src/docs.rs
@@ -106,6 +106,7 @@ docs! {
     "derive_hash_xor_eq",
     "derive_ord_xor_partial_ord",
     "derive_partial_eq_without_eq",
+    "disallowed_macros",
     "disallowed_methods",
     "disallowed_names",
     "disallowed_script_idents",
diff --git a/src/docs/disallowed_macros.txt b/src/docs/disallowed_macros.txt
new file mode 100644
index 00000000000..96fa15afabf
--- /dev/null
+++ b/src/docs/disallowed_macros.txt
@@ -0,0 +1,36 @@
+### What it does
+Denies the configured macros in clippy.toml
+
+Note: Even though this lint is warn-by-default, it will only trigger if
+macros are defined in the clippy.toml file.
+
+### Why is this bad?
+Some macros are undesirable in certain contexts, and it's beneficial to
+lint for them as needed.
+
+### Example
+An example clippy.toml configuration:
+```
+disallowed-macros = [
+    # Can use a string as the path of the disallowed macro.
+    "std::print",
+    # Can also use an inline table with a `path` key.
+    { path = "std::println" },
+    # When using an inline table, can add a `reason` for why the macro
+    # is disallowed.
+    { path = "serde::Serialize", reason = "no serializing" },
+]
+```
+```
+use serde::Serialize;
+
+// Example code where clippy issues a warning
+println!("warns");
+
+// The diagnostic will contain the message "no serializing"
+#[derive(Serialize)]
+struct Data {
+    name: String,
+    value: usize,
+}
+```
\ No newline at end of file
diff --git a/tests/ui-toml/disallowed_macros/auxiliary/macros.rs b/tests/ui-toml/disallowed_macros/auxiliary/macros.rs
new file mode 100644
index 00000000000..fcaeace0e98
--- /dev/null
+++ b/tests/ui-toml/disallowed_macros/auxiliary/macros.rs
@@ -0,0 +1,32 @@
+#[macro_export]
+macro_rules! expr {
+    () => {
+        1
+    };
+}
+
+#[macro_export]
+macro_rules! stmt {
+    () => {
+        let _x = ();
+    };
+}
+
+#[macro_export]
+macro_rules! ty {
+    () => { &'static str };
+}
+
+#[macro_export]
+macro_rules! pat {
+    () => {
+        _
+    };
+}
+
+#[macro_export]
+macro_rules! item {
+    () => {
+        const ITEM: usize = 1;
+    };
+}
diff --git a/tests/ui-toml/disallowed_macros/clippy.toml b/tests/ui-toml/disallowed_macros/clippy.toml
new file mode 100644
index 00000000000..c8fe8be9a77
--- /dev/null
+++ b/tests/ui-toml/disallowed_macros/clippy.toml
@@ -0,0 +1,11 @@
+disallowed-macros = [
+    "std::println",
+    "std::vec",
+    { path = "std::cfg" },
+    { path = "serde::Serialize", reason = "no serializing" },
+    "macros::expr",
+    "macros::stmt",
+    "macros::ty",
+    "macros::pat",
+    "macros::item",
+]
diff --git a/tests/ui-toml/disallowed_macros/disallowed_macros.rs b/tests/ui-toml/disallowed_macros/disallowed_macros.rs
new file mode 100644
index 00000000000..2bb5376076e
--- /dev/null
+++ b/tests/ui-toml/disallowed_macros/disallowed_macros.rs
@@ -0,0 +1,39 @@
+// aux-build:macros.rs
+
+#![allow(unused)]
+
+extern crate macros;
+
+use serde::Serialize;
+
+fn main() {
+    println!("one");
+    println!("two");
+    cfg!(unix);
+    vec![1, 2, 3];
+
+    #[derive(Serialize)]
+    struct Derive;
+
+    let _ = macros::expr!();
+    macros::stmt!();
+    let macros::pat!() = 1;
+    let _: macros::ty!() = "";
+    macros::item!();
+
+    eprintln!("allowed");
+}
+
+struct S;
+
+impl S {
+    macros::item!();
+}
+
+trait Y {
+    macros::item!();
+}
+
+impl Y for S {
+    macros::item!();
+}
diff --git a/tests/ui-toml/disallowed_macros/disallowed_macros.stderr b/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
new file mode 100644
index 00000000000..aed9feb6f79
--- /dev/null
+++ b/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
@@ -0,0 +1,84 @@
+error: use of a disallowed macro `std::println`
+  --> $DIR/disallowed_macros.rs:10:5
+   |
+LL |     println!("one");
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::disallowed-macros` implied by `-D warnings`
+
+error: use of a disallowed macro `std::println`
+  --> $DIR/disallowed_macros.rs:11:5
+   |
+LL |     println!("two");
+   |     ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `std::cfg`
+  --> $DIR/disallowed_macros.rs:12:5
+   |
+LL |     cfg!(unix);
+   |     ^^^^^^^^^^
+
+error: use of a disallowed macro `std::vec`
+  --> $DIR/disallowed_macros.rs:13:5
+   |
+LL |     vec![1, 2, 3];
+   |     ^^^^^^^^^^^^^
+
+error: use of a disallowed macro `serde::Serialize`
+  --> $DIR/disallowed_macros.rs:15:14
+   |
+LL |     #[derive(Serialize)]
+   |              ^^^^^^^^^
+   |
+   = note: no serializing (from clippy.toml)
+
+error: use of a disallowed macro `macros::expr`
+  --> $DIR/disallowed_macros.rs:18:13
+   |
+LL |     let _ = macros::expr!();
+   |             ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::stmt`
+  --> $DIR/disallowed_macros.rs:19:5
+   |
+LL |     macros::stmt!();
+   |     ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::pat`
+  --> $DIR/disallowed_macros.rs:20:9
+   |
+LL |     let macros::pat!() = 1;
+   |         ^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::ty`
+  --> $DIR/disallowed_macros.rs:21:12
+   |
+LL |     let _: macros::ty!() = "";
+   |            ^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::item`
+  --> $DIR/disallowed_macros.rs:22:5
+   |
+LL |     macros::item!();
+   |     ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::item`
+  --> $DIR/disallowed_macros.rs:30:5
+   |
+LL |     macros::item!();
+   |     ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::item`
+  --> $DIR/disallowed_macros.rs:34:5
+   |
+LL |     macros::item!();
+   |     ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::item`
+  --> $DIR/disallowed_macros.rs:38:5
+   |
+LL |     macros::item!();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
diff --git a/tests/ui-toml/toml_disallowed_methods/clippy.toml b/tests/ui-toml/toml_disallowed_methods/clippy.toml
index c902d21123d..28774db625b 100644
--- a/tests/ui-toml/toml_disallowed_methods/clippy.toml
+++ b/tests/ui-toml/toml_disallowed_methods/clippy.toml
@@ -3,6 +3,7 @@ disallowed-methods = [
     "std::iter::Iterator::sum",
     "f32::clamp",
     "slice::sort_unstable",
+    "futures::stream::select_all",
     # can give path and reason with an inline table
     { path = "regex::Regex::is_match", reason = "no matching allowed" },
     # can use an inline table but omit reason
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 3397fa1ec69..b483f160028 100644
--- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
+++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
@@ -1,6 +1,9 @@
 #![warn(clippy::disallowed_methods)]
 
+extern crate futures;
 extern crate regex;
+
+use futures::stream::{empty, select_all};
 use regex::Regex;
 
 fn main() {
@@ -20,4 +23,7 @@ fn main() {
 
     let in_call = Box::new(f32::clamp);
     let in_method_call = ["^", "$"].into_iter().map(Regex::new);
+
+    // resolve ambiguity between `futures::stream::select_all` the module and the function
+    let same_name_as_module = select_all(vec![empty::<()>()]);
 }
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 5cbb567546c..6d78c32e127 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:7:14
+  --> $DIR/conf_disallowed_methods.rs:10: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:8:5
+  --> $DIR/conf_disallowed_methods.rs:11:5
    |
 LL |     re.is_match("abc");
    |     ^^^^^^^^^^^^^^^^^^
@@ -15,40 +15,46 @@ 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:11:5
+  --> $DIR/conf_disallowed_methods.rs:14:5
    |
 LL |     a.iter().sum::<i32>();
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `slice::sort_unstable`
-  --> $DIR/conf_disallowed_methods.rs:13:5
+  --> $DIR/conf_disallowed_methods.rs:16:5
    |
 LL |     a.sort_unstable();
    |     ^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> $DIR/conf_disallowed_methods.rs:15:13
+  --> $DIR/conf_disallowed_methods.rs:18:13
    |
 LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> $DIR/conf_disallowed_methods.rs:18:61
+  --> $DIR/conf_disallowed_methods.rs:21: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:21:28
+  --> $DIR/conf_disallowed_methods.rs:24:28
    |
 LL |     let in_call = Box::new(f32::clamp);
    |                            ^^^^^^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> $DIR/conf_disallowed_methods.rs:22:53
+  --> $DIR/conf_disallowed_methods.rs:25:53
    |
 LL |     let in_method_call = ["^", "$"].into_iter().map(Regex::new);
    |                                                     ^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: use of a disallowed method `futures::stream::select_all`
+  --> $DIR/conf_disallowed_methods.rs:28:31
+   |
+LL |     let same_name_as_module = select_all(vec![empty::<()>()]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index f27f78d15d3..82ee8054132 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -11,6 +11,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            cargo-ignore-publish
            cognitive-complexity-threshold
            cyclomatic-complexity-threshold
+           disallowed-macros
            disallowed-methods
            disallowed-names
            disallowed-types