From 73b06395440952a1d3e6b1f711023c61d00f631b Mon Sep 17 00:00:00 2001 From: Stepan Tubanov Date: Wed, 27 Mar 2024 14:32:43 +0400 Subject: [PATCH] Add conf to disable `disallowed_types` in macros --- clippy_config/src/conf.rs | 4 ++ clippy_lints/src/disallowed_types.rs | 22 +++++++++- clippy_lints/src/lib.rs | 8 +++- .../auxiliary/proc_macro_attr.rs | 18 ++++++++ .../ui-toml/toml_disallowed_types/clippy.toml | 1 + .../conf_disallowed_types.rs | 6 +++ .../conf_disallowed_types.stderr | 42 +++++++++---------- 7 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 tests/ui-toml/toml_disallowed_types/auxiliary/proc_macro_attr.rs diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 93ca535a7a46..45b55499bd2c 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -400,6 +400,10 @@ define_Conf! { /// /// The list of disallowed types, written as fully qualified paths. (disallowed_types: Vec = Vec::new()), + /// Lint: DISALLOWED_TYPES. + /// + /// Enables lint in external macros. + (lint_disallowed_types_in_external_macros: bool = true), /// Lint: UNREADABLE_LITERAL. /// /// Should the fraction of a decimal be linted to include separators. diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 4196309a22a4..66df0b190df0 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -1,3 +1,4 @@ +use crate::rustc_lint::LintContext; use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashMap; @@ -5,6 +6,7 @@ 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}; +use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -52,14 +54,16 @@ declare_clippy_lint! { #[derive(Clone, Debug)] pub struct DisallowedTypes { conf_disallowed: Vec, + conf_lint_external_macros: bool, def_ids: FxHashMap, prim_tys: FxHashMap, } impl DisallowedTypes { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(conf_disallowed: Vec, conf_lint_external_macros: bool) -> Self { Self { conf_disallowed, + conf_lint_external_macros, def_ids: FxHashMap::default(), prim_tys: FxHashMap::default(), } @@ -105,6 +109,12 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Use(path, UseKind::Single) = &item.kind { + if !self.conf_lint_external_macros + && (in_external_macro(cx.sess(), item.span) || clippy_utils::is_from_proc_macro(cx, item)) + { + return; + } + for res in &path.res { self.check_res_emit(cx, res, item.span); } @@ -113,11 +123,21 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { if let TyKind::Path(path) = &ty.kind { + if !self.conf_lint_external_macros + && (in_external_macro(cx.sess(), ty.span) || clippy_utils::is_from_proc_macro(cx, ty)) + { + return; + } + self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span); } } fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { + if !self.conf_lint_external_macros && in_external_macro(cx.sess(), poly.span) { + return; + } + self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span); } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1bd6dfe24617..5fe0556050ea 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -557,6 +557,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { ref disallowed_methods, ref disallowed_names, ref disallowed_types, + lint_disallowed_types_in_external_macros, ref doc_valid_idents, enable_raw_pointer_heuristic_for_send, enforce_iter_loop_reborrow, @@ -958,7 +959,12 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison)); store.register_early_pass(move || Box::new(module_style::ModStyle)); store.register_late_pass(|_| Box::::default()); - store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone()))); + store.register_late_pass(move |_| { + Box::new(disallowed_types::DisallowedTypes::new( + disallowed_types.clone(), + lint_disallowed_types_in_external_macros, + )) + }); store.register_late_pass(move |_| { Box::new(missing_enforced_import_rename::ImportRename::new( enforced_import_renames.clone(), diff --git a/tests/ui-toml/toml_disallowed_types/auxiliary/proc_macro_attr.rs b/tests/ui-toml/toml_disallowed_types/auxiliary/proc_macro_attr.rs new file mode 100644 index 000000000000..90bc73c23aea --- /dev/null +++ b/tests/ui-toml/toml_disallowed_types/auxiliary/proc_macro_attr.rs @@ -0,0 +1,18 @@ +extern crate proc_macro; +extern crate quote; + +use proc_macro::TokenStream; +use quote::quote; + +#[proc_macro_attribute] +pub fn use_std_hash_map(_args: TokenStream, input: TokenStream) -> TokenStream { + TokenStream::from_iter([ + input, + quote!( + pub fn new_function() { + let _ = std::collections::HashMap::::default(); + } + ) + .into(), + ]) +} diff --git a/tests/ui-toml/toml_disallowed_types/clippy.toml b/tests/ui-toml/toml_disallowed_types/clippy.toml index 6cb9e2ef9546..e1e76dd99ef2 100644 --- a/tests/ui-toml/toml_disallowed_types/clippy.toml +++ b/tests/ui-toml/toml_disallowed_types/clippy.toml @@ -13,3 +13,4 @@ disallowed-types = [ # can use an inline table but omit reason { path = "std::net::TcpListener" }, ] +lint-disallowed-types-in-external-macros = false \ No newline at end of file diff --git a/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs b/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs index f02bd07cfe7b..375c6930fb91 100644 --- a/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs +++ b/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs @@ -1,5 +1,7 @@ +//@aux-build:proc_macro_attr.rs #![warn(clippy::disallowed_types)] +extern crate proc_macro_attr; extern crate quote; extern crate syn; @@ -39,6 +41,10 @@ fn main() { let _ = syn::Ident::new("", todo!()); let _ = HashMap; let _: usize = 64_usize; + + // Lint should not report usage of std::collections::HashMap inside a foreign macro + #[proc_macro_attr::use_std_hash_map] + fn _foo() {} } mod useless_attribute { diff --git a/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr b/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr index 20df8e88d36b..c43469806728 100644 --- a/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr +++ b/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr @@ -1,5 +1,5 @@ error: `std::sync::atomic::AtomicU32` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:7:1 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:9:1 | LL | use std::sync::atomic::AtomicU32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,61 +8,61 @@ LL | use std::sync::atomic::AtomicU32; = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` error: `std::time::Instant` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:8:1 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:10:1 | LL | use std::time::Instant as Sneaky; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `std::time::Instant` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:12:33 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:14:33 | LL | fn bad_return_type() -> fn() -> Sneaky { | ^^^^^^ error: `std::time::Instant` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:16:28 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:18:28 | LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {} | ^^^^^^ error: `std::sync::atomic::AtomicU32` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:16:39 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:18:39 | LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {} | ^^^^^^^^^^^^^^^^^^^^^^ error: `std::io::Read` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:18:22 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:20:22 | LL | fn trait_obj(_: &dyn std::io::Read) {} | ^^^^^^^^^^^^^ error: `usize` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:20:33 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:22:33 | LL | fn full_and_single_path_prim(_: usize, _: bool) {} | ^^^^^ error: `bool` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:20:43 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:22:43 | LL | fn full_and_single_path_prim(_: usize, _: bool) {} | ^^^^ error: `usize` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:22:28 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:24:28 | LL | fn const_generics() {} | ^^^^^ error: `usize` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:24:24 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:26:24 | LL | struct GenArg([u8; U]); | ^^^^^ error: `std::net::Ipv4Addr` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:28:10 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:30:10 | LL | fn ip(_: std::net::Ipv4Addr) {} | ^^^^^^^^^^^^^^^^^^ @@ -70,61 +70,61 @@ LL | fn ip(_: std::net::Ipv4Addr) {} = note: no IPv4 allowed (from clippy.toml) error: `std::net::TcpListener` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:30:16 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:32:16 | LL | fn listener(_: std::net::TcpListener) {} | ^^^^^^^^^^^^^^^^^^^^^ error: `std::collections::HashMap` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:34:48 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:36:48 | LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `std::collections::HashMap` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:34:12 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:36:12 | LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `std::time::Instant` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:35:13 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:37:13 | LL | let _ = Sneaky::now(); | ^^^^^^ error: `std::sync::atomic::AtomicU32` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:36:13 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:38:13 | LL | let _ = foo::atomic::AtomicU32::new(0); | ^^^^^^^^^^^^^^^^^^^^^^ error: `std::sync::atomic::AtomicU32` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:37:17 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:39:17 | LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `std::sync::atomic::AtomicU32` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:37:48 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:39:48 | LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1); | ^^^^^^^^^^^^^^^^^^^^^^ error: `syn::TypePath` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:38:43 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:40:43 | LL | let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default(); | ^^^^^^^^^^^^^ error: `syn::Ident` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:39:13 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:41:13 | LL | let _ = syn::Ident::new("", todo!()); | ^^^^^^^^^^ error: `usize` is not allowed according to config - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:41:12 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:43:12 | LL | let _: usize = 64_usize; | ^^^^^