diff --git a/CHANGELOG.md b/CHANGELOG.md index d06a72d9c415..8fb6356ff8e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7609,7 +7609,6 @@ Released 2018-09-13 [`module-items-ordered-within-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-items-ordered-within-groupings [`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv [`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit -[`profiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#profiles [`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior [`recursive-self-in-type-definitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#recursive-self-in-type-definitions [`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index e123d7ba5704..dd10ef0538c2 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -986,28 +986,6 @@ The minimum size (in bytes) to consider a type for passing by reference instead * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) -## `profiles` -Named profiles of disallowed items (unrelated to Cargo build profiles). - -#### Example - -```toml -[profiles.persistent] -disallowed-methods = [{ path = "std::env::temp_dir" }] -disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }] - -[profiles.single_threaded] -disallowed-methods = [{ path = "std::thread::spawn" }] -``` - -**Default Value:** `{}` - ---- -**Affected lints:** -* [`disallowed_methods`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) -* [`disallowed_types`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) - - ## `pub-underscore-fields-behavior` Lint "public" fields in a struct that are prefixed with an underscore based on their exported visibility, or whether they are marked as "pub". diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 47bc7b572c9d..5a06cb477c30 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,13 +1,12 @@ use crate::ClippyConfiguration; use crate::types::{ - DisallowedPath, DisallowedPathWithoutReplacement, DisallowedProfile, InherentImplLintScope, MacroMatcher, - MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, + DisallowedPath, DisallowedPathWithoutReplacement, InherentImplLintScope, MacroMatcher, MatchLintBehaviour, + PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds, SourceItemOrderingWithinModuleItemGroupings, }; use clippy_utils::msrvs::Msrv; use itertools::Itertools; -use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; @@ -223,74 +222,12 @@ macro_rules! deserialize { }}; } -macro_rules! parse_conf_value { - ( - $map:expr, - $ty:ty, - $errors:expr, - $file:expr, - $field_span:expr, - profiles @[$($profiles:expr)?], - disallowed @[$($disallowed:expr)?] - ) => { - parse_conf_value_impl!( - $map, - $ty, - $errors, - $file, - $field_span, - ($($profiles)?), - ($($disallowed)?) - ) - }; -} - -macro_rules! parse_conf_value_impl { - ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, (), ()) => {{ - let _ = &$field_span; - deserialize!($map, $ty, $errors, $file) - }}; - ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, ($profiles:expr), ()) => {{ - let raw_value = $map.next_value::()?; - let value_span = $field_span.clone(); - let toml::Value::Table(table) = raw_value else { - $errors.push(ConfError::spanned( - $file, - "expected table with named profiles", - None, - value_span.clone(), - )); - continue; - }; - - let map = parse_profiles(table, $file, value_span.clone(), &mut $errors); - - (map, value_span) - }}; - ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, (), ($disallowed:expr)) => {{ - let _ = &$field_span; - deserialize!($map, $ty, $errors, $file, $disallowed) - }}; - ( - $map:expr, - $ty:ty, - $errors:expr, - $file:expr, - $field_span:expr, - ($profiles:expr), - ($disallowed:expr) - ) => { - compile_error!("field cannot specify both profiles and disallowed-paths attributes") - }; -} - macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])? $(#[default_text = $default_text:expr])? $(#[disallowed_paths_allow_replacements = $replacements_allowed:expr])? - $(#[profiles = $profiles:expr])? $(#[lints($($for_lints:ident),* $(,)?)])? $name:ident: $ty:ty = $default:expr, )*) => { @@ -345,20 +282,10 @@ macro_rules! define_Conf { match field { $(Field::$name => { - let field_span = name.span(); // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning. $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), None, name.span()));)? - let (value, value_span) = parse_conf_value!( - map, - $ty, - errors, - self.0, - field_span, - // Disallowed-profile table parsing is special-cased to preserve spans for - // diagnostics in disallowed-path entries. - profiles @[$($profiles)?], - disallowed @[$($replacements_allowed)?] - ); + let (value, value_span) = + deserialize!(map, $ty, errors, self.0 $(, $replacements_allowed)?); // Was this field set previously? if $name.is_some() { errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span())); @@ -415,121 +342,6 @@ fn span_from_toml_range(file: &SourceFile, span: Range) -> Span { ) } -fn parse_profiles( - table: toml::value::Table, - file: &SourceFile, - value_span: Range, - errors: &mut Vec, -) -> FxHashMap { - let mut profiles = FxHashMap::default(); - let config_span = span_from_toml_range(file, value_span.clone()); - - for (profile_name, profile_value) in table { - let toml::Value::Table(mut profile_table) = profile_value else { - errors.push(ConfError::spanned( - file, - format!("invalid profile `{profile_name}`: expected table"), - None, - value_span.clone(), - )); - continue; - }; - - let disallowed_methods = match profile_table - .remove("disallowed-methods") - .or_else(|| profile_table.remove("disallowed_methods")) - { - Some(value) => parse_profile_list( - file, - &profile_name, - "disallowed-methods", - value, - value_span.clone(), - config_span, - errors, - ), - None => Vec::new(), - }; - - let disallowed_types = match profile_table - .remove("disallowed-types") - .or_else(|| profile_table.remove("disallowed_types")) - { - Some(value) => parse_profile_list( - file, - &profile_name, - "disallowed-types", - value, - value_span.clone(), - config_span, - errors, - ), - None => Vec::new(), - }; - - if !profile_table.is_empty() { - let keys = profile_table.keys().map(String::as_str).collect::>().join(", "); - errors.push(ConfError::spanned( - file, - format!("profile `{profile_name}` has unknown keys: {keys}"), - None, - value_span.clone(), - )); - } - - profiles.insert( - profile_name, - DisallowedProfile { - disallowed_methods, - disallowed_types, - }, - ); - } - - profiles -} - -fn parse_profile_list( - file: &SourceFile, - profile_name: &str, - key_name: &str, - value: toml::Value, - value_span: Range, - config_span: Span, - errors: &mut Vec, -) -> Vec { - let toml::Value::Array(entries) = value else { - errors.push(ConfError::spanned( - file, - format!("profile `{profile_name}`: `{key_name}` must be an array"), - None, - value_span, - )); - return Vec::new(); - }; - - let mut disallowed = Vec::with_capacity(entries.len()); - for entry in entries { - match DisallowedPath::deserialize(entry.clone()) { - Ok(mut path) => { - path.set_span(config_span); - disallowed.push(path); - }, - Err(err) => errors.push(ConfError::spanned( - file, - format!( - "profile `{profile_name}`: {}", - err.to_string().replace('\n', " ").trim() - ), - None, - value_span.clone(), - )), - } - } - - disallowed -} - define_Conf! { /// Which crates to allow absolute paths from #[lints(absolute_paths)] @@ -1029,21 +841,6 @@ define_Conf! { /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. #[lints(large_types_passed_by_value)] pass_by_value_size_limit: u64 = 256, - /// Named profiles of disallowed items (unrelated to Cargo build profiles). - /// - /// #### Example - /// - /// ```toml - /// [profiles.persistent] - /// disallowed-methods = [{ path = "std::env::temp_dir" }] - /// disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }] - /// - /// [profiles.single_threaded] - /// disallowed-methods = [{ path = "std::thread::spawn" }] - /// ``` - #[profiles = true] - #[lints(disallowed_methods, disallowed_types)] - profiles: FxHashMap = FxHashMap::default(), /// Lint "public" fields in a struct that are prefixed with an underscore based on their /// exported visibility, or whether they are marked as "pub". #[lints(pub_underscore_fields)] diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 5eaa44ddd51d..8d9326a904b1 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -57,15 +57,6 @@ impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath, - #[serde(default, alias = "disallowed_types")] - pub disallowed_types: Vec, -} - // `DisallowedPathEnum` is an implementation detail to enable the `Deserialize` implementation just // above. `DisallowedPathEnum` is not meant to be used outside of this file. #[derive(Debug, Deserialize, Serialize)] diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 58cc318d57cc..e2fd71b7d990 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,18 +1,13 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::paths::PathNS; -use clippy_utils::sym; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::smallvec::SmallVec; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -60,19 +55,6 @@ declare_clippy_lint! { /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. /// xs.push(123); // Vec::push is _not_ disallowed in the config. /// ``` - /// - /// Disallowed profiles allow scoping different disallow lists: - /// ```toml - /// [profiles.forward_pass] - /// disallowed-methods = [{ path = "crate::devices::Buffer::copy_to_host", reason = "Forward code must not touch host buffers" }] - /// ``` - /// - /// ```rust,ignore - /// #[clippy::disallowed_profile("forward_pass")] - /// fn evaluate() { - /// // Method calls in this function use the `forward_pass` profile. - /// } - /// ``` #[clippy::version = "1.49.0"] pub DISALLOWED_METHODS, style, @@ -82,22 +64,12 @@ declare_clippy_lint! { impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); pub struct DisallowedMethods { - default: DefIdMap<(&'static str, &'static DisallowedPath)>, - /// Lookup per profile that declares a non-empty `disallowed_methods` list. Profiles - /// declared in `[profiles.*]` but without `disallowed_methods` entries are absent here. - profiles: FxHashMap>, - /// Every profile name declared in `[profiles.*]`, regardless of whether it contributes - /// to this lint. Used to suppress the "unknown profile" warning for profiles that exist - /// in config but only define entries for other lints (e.g. `disallowed_types`). - known_profiles: FxHashSet, - profile_cache: ProfileResolver, - warned_unknown_profiles: FxHashSet, + disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, } impl DisallowedMethods { - #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration. pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let (default, _) = create_disallowed_map( + let (disallowed, _) = create_disallowed_map( tcx, &conf.disallowed_methods, PathNS::Value, @@ -110,62 +82,7 @@ impl DisallowedMethods { "function", false, ); - - let mut profiles = FxHashMap::default(); - let mut known_profiles = FxHashSet::default(); - let mut profile_entries: Vec<_> = conf.profiles.iter().collect(); - profile_entries.sort_by_key(|(a, _)| *a); - for (name, profile) in profile_entries { - let symbol = Symbol::intern(name.as_str()); - known_profiles.insert(symbol); - - let paths = profile.disallowed_methods.as_slice(); - if paths.is_empty() { - continue; - } - - let (map, _) = create_disallowed_map( - tcx, - paths, - PathNS::Value, - |def_kind| { - matches!( - def_kind, - DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn - ) - }, - "function", - false, - ); - profiles.insert(symbol, map); - } - - Self { - default, - profiles, - known_profiles, - profile_cache: ProfileResolver::default(), - warned_unknown_profiles: FxHashSet::default(), - } - } - - fn warn_unknown_profile(&mut self, cx: &LateContext<'_>, entry: &ProfileEntry) { - if self.warned_unknown_profiles.insert(entry.span) { - let attr_name = if entry.attr_name == sym::disallowed_profiles { - "clippy::disallowed_profiles" - } else { - "clippy::disallowed_profile" - }; - span_lint( - cx, - DISALLOWED_METHODS, - entry.span, - format!( - "`{attr_name}` references unknown profile `{}` for `clippy::disallowed_methods`", - entry.name - ), - ); - } + Self { disallowed } } } @@ -181,43 +98,13 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { }, _ => return, }; - let mut active_profiles = SmallVec::<[Symbol; 2]>::new(); - // Copy entries out of the cache before iterating: `warn_unknown_profile` takes - // `&mut self`, which conflicts with the borrow held by `active_profiles(...)`. - let entries: SmallVec<[ProfileEntry; 2]> = self - .profile_cache - .active_profiles(cx, expr.hir_id) - .map(|selection| selection.iter().copied().collect()) - .unwrap_or_default(); - for entry in &entries { - if self.profiles.contains_key(&entry.name) { - active_profiles.push(entry.name); - } else if !self.known_profiles.contains(&entry.name) { - self.warn_unknown_profile(cx, entry); - } - } - - if let Some((profile, &(path, disallowed_path))) = active_profiles.iter().find_map(|symbol| { - self.profiles - .get(symbol) - .and_then(|map| map.get(&id).map(|info| (*symbol, info))) - }) { - let diag_amendment = disallowed_path.diag_amendment(span); - span_lint_and_then( - cx, - DISALLOWED_METHODS, - span, - format!("use of a disallowed method `{path}` (profile: {profile})"), - |diag| diag_amendment(diag), - ); - } else if let Some(&(path, disallowed_path)) = self.default.get(&id) { - let diag_amendment = disallowed_path.diag_amendment(span); + if let Some(&(path, disallowed_path)) = self.disallowed.get(&id) { span_lint_and_then( cx, DISALLOWED_METHODS, span, format!("use of a disallowed method `{path}`"), - |diag| diag_amendment(diag), + disallowed_path.diag_amendment(span), ); } } diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 37dd605617a7..2c520d053f43 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -1,18 +1,15 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::paths::PathNS; -use clippy_utils::sym; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::smallvec::SmallVec; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -54,17 +51,6 @@ declare_clippy_lint! { /// // A similar type that is allowed by the config /// use std::collections::HashMap; /// ``` - /// - /// Disallowed profiles can scope lists to specific modules: - /// ```toml - /// [profiles.forward_pass] - /// disallowed-types = [{ path = "crate::buffers::HostBuffer", reason = "Prefer device buffers in forward computations" }] - /// ``` - /// - /// ```rust,ignore - /// #[clippy::disallowed_profile("forward_pass")] - /// fn forward_step(buffer: crate::buffers::DeviceBuffer) { /* ... */ } - /// ``` #[clippy::version = "1.55.0"] pub DISALLOWED_TYPES, style, @@ -73,127 +59,37 @@ declare_clippy_lint! { impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]); -struct TypeLookup { +pub struct DisallowedTypes { def_ids: DefIdMap<(&'static str, &'static DisallowedPath)>, prim_tys: FxHashMap, } -impl TypeLookup { - fn from_config(tcx: TyCtxt<'_>, paths: &'static [DisallowedPath]) -> Self { - let (def_ids, prim_tys) = create_disallowed_map(tcx, paths, PathNS::Type, def_kind_predicate, "type", true); - Self { def_ids, prim_tys } - } - - fn find(&self, res: &Res) -> Option<(&'static str, &'static DisallowedPath)> { - match res { - Res::Def(_, did) => self.def_ids.get(did).copied(), - Res::PrimTy(prim) => self.prim_tys.get(prim).copied(), - _ => None, - } - } -} - -pub struct DisallowedTypes { - default: TypeLookup, - /// Lookup per profile that declares a non-empty `disallowed_types` list. Profiles - /// declared in `[profiles.*]` but without `disallowed_types` entries are absent here. - profiles: FxHashMap, - /// Every profile name declared in `[profiles.*]`, regardless of whether it contributes - /// to this lint. Used to suppress the "unknown profile" warning for profiles that exist - /// in config but only define entries for other lints (e.g. `disallowed_methods`). - known_profiles: FxHashSet, - profile_cache: ProfileResolver, - warned_unknown_profiles: FxHashSet, -} - impl DisallowedTypes { - #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration. pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let default = TypeLookup::from_config(tcx, &conf.disallowed_types); - - let mut profiles = FxHashMap::default(); - let mut known_profiles = FxHashSet::default(); - let mut profile_entries: Vec<_> = conf.profiles.iter().collect(); - profile_entries.sort_by_key(|(a, _)| *a); - for (name, profile) in profile_entries { - let symbol = Symbol::intern(name.as_str()); - known_profiles.insert(symbol); - - let paths = profile.disallowed_types.as_slice(); - if paths.is_empty() { - continue; - } - profiles.insert(symbol, TypeLookup::from_config(tcx, paths)); - } - - Self { - default, - profiles, - known_profiles, - profile_cache: ProfileResolver::default(), - warned_unknown_profiles: FxHashSet::default(), - } - } - - fn warn_unknown_profile(&mut self, cx: &LateContext<'_>, entry: &ProfileEntry) { - if self.warned_unknown_profiles.insert(entry.span) { - let attr_name = if entry.attr_name == sym::disallowed_profiles { - "clippy::disallowed_profiles" - } else { - "clippy::disallowed_profile" - }; - span_lint( - cx, - DISALLOWED_TYPES, - entry.span, - format!( - "`{attr_name}` references unknown profile `{}` for `clippy::disallowed_types`", - entry.name - ), - ); - } + let (def_ids, prim_tys) = create_disallowed_map( + tcx, + &conf.disallowed_types, + PathNS::Type, + def_kind_predicate, + "type", + true, + ); + Self { def_ids, prim_tys } } - fn check_res_emit(&mut self, cx: &LateContext<'_>, hir_id: rustc_hir::HirId, res: &Res, span: Span) { - let mut active_profiles = SmallVec::<[Symbol; 2]>::new(); - // Copy entries out of the cache before iterating: `warn_unknown_profile` takes - // `&mut self`, which conflicts with the borrow held by `active_profiles(...)`. - let entries: SmallVec<[ProfileEntry; 2]> = self - .profile_cache - .active_profiles(cx, hir_id) - .map(|selection| selection.iter().copied().collect()) - .unwrap_or_default(); - for entry in &entries { - if self.profiles.contains_key(&entry.name) { - active_profiles.push(entry.name); - } else if !self.known_profiles.contains(&entry.name) { - self.warn_unknown_profile(cx, entry); - } - } - - if let Some((profile, (path, disallowed_path))) = active_profiles.iter().find_map(|symbol| { - self.profiles - .get(symbol) - .and_then(|lookup| lookup.find(res).map(|info| (*symbol, info))) - }) { - let diag_amendment = disallowed_path.diag_amendment(span); - span_lint_and_then( - cx, - DISALLOWED_TYPES, - span, - format!("use of a disallowed type `{path}` (profile: {profile})"), - |diag| diag_amendment(diag), - ); - } else if let Some((path, disallowed_path)) = self.default.find(res) { - let diag_amendment = disallowed_path.diag_amendment(span); - span_lint_and_then( - cx, - DISALLOWED_TYPES, - span, - format!("use of a disallowed type `{path}`"), - |diag| diag_amendment(diag), - ); - } + fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) { + let (path, disallowed_path) = match res { + Res::Def(_, did) if let Some(&x) = self.def_ids.get(did) => x, + Res::PrimTy(prim) if let Some(&x) = self.prim_tys.get(prim) => x, + _ => return, + }; + span_lint_and_then( + cx, + DISALLOWED_TYPES, + span, + format!("use of a disallowed type `{path}`"), + disallowed_path.diag_amendment(span), + ); } } @@ -215,22 +111,17 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind && let Some(res) = path.res.type_ns { - self.check_res_emit(cx, item.hir_id(), &res, item.span); + self.check_res_emit(cx, &res, item.span); } } fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) { if let TyKind::Path(path) = &ty.kind { - self.check_res_emit(cx, ty.hir_id, &cx.qpath_res(path, ty.hir_id), ty.span); + 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>) { - self.check_res_emit( - cx, - poly.trait_ref.hir_ref_id, - &poly.trait_ref.path.res, - poly.trait_ref.path.span, - ); + self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span); } } diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2341007cd49e..ca3ed73b8481 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -37,8 +37,6 @@ pub fn check_clippy_attr(sess: &Session, attr: &A) { | sym::version | sym::cognitive_complexity | sym::dump - | sym::disallowed_profile - | sym::disallowed_profiles | sym::msrv | sym::has_significant_drop | sym::format_args => {}, diff --git a/clippy_utils/src/disallowed_profiles.rs b/clippy_utils/src/disallowed_profiles.rs deleted file mode 100644 index 98a498981b3b..000000000000 --- a/clippy_utils/src/disallowed_profiles.rs +++ /dev/null @@ -1,180 +0,0 @@ -use crate::sym; -use rustc_ast::ast::{LitKind, MetaItemInner}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::smallvec::SmallVec; -use rustc_hir::{Attribute, HirId}; -use rustc_lint::LateContext; -use rustc_span::{Span, Symbol}; - -/// One profile name referenced by a `#[clippy::disallowed_profile(...)]` or -/// `#[clippy::disallowed_profiles(...)]` attribute on an item. -/// -/// A single attribute produces one `ProfileEntry` per string argument. The entry records which -/// attribute variant introduced it, the profile name, and the span of that string literal so -/// diagnostics (e.g. "unknown profile") can point at the exact argument. -#[derive(Copy, Clone)] -pub struct ProfileEntry { - pub attr_name: Symbol, - pub name: Symbol, - pub span: Span, -} - -/// The set of profiles active at some `HirId`, obtained by walking up the HIR from that id and -/// collecting the first ancestor that carries a `#[clippy::disallowed_profile(s)]` attribute. -/// -/// An empty selection is represented by `None` at the call site; a `ProfileSelection` is always -/// non-empty. -#[derive(Clone)] -pub struct ProfileSelection { - entries: SmallVec<[ProfileEntry; 2]>, -} - -impl ProfileSelection { - pub fn new(entries: SmallVec<[ProfileEntry; 2]>) -> Self { - Self { entries } - } - - pub fn is_empty(&self) -> bool { - self.entries.is_empty() - } - - pub fn iter(&self) -> impl Iterator { - self.entries.iter() - } -} - -#[derive(Default)] -pub struct ProfileResolver { - cache: FxHashMap>, -} - -impl ProfileResolver { - pub fn active_profiles(&mut self, cx: &LateContext<'_>, hir_id: HirId) -> Option<&ProfileSelection> { - // NOTE: The `contains_key`+`get` dance is intentional: using only `get` here triggers borrowck - // errors because we need to mutate `self.cache` on cache misses. - if self.cache.contains_key(&hir_id) { - return self.cache.get(&hir_id).and_then(|selection| selection.as_ref()); - } - - let (resolved, visited) = self.resolve(cx, hir_id); - - for id in visited { - self.cache.entry(id).or_insert_with(|| resolved.clone()); - } - self.cache.insert(hir_id, resolved); - - self.cache.get(&hir_id).and_then(|selection| selection.as_ref()) - } - - fn resolve(&self, cx: &LateContext<'_>, start: HirId) -> (Option, SmallVec<[HirId; 8]>) { - let mut visited = SmallVec::<[HirId; 8]>::new(); - let mut current = Some(start); - - while let Some(id) = current { - if let Some(cached) = self.cache.get(&id) { - return (cached.clone(), visited); - } - - visited.push(id); - - if let Some(selection) = profiles_from_attrs(cx, cx.tcx.hir_attrs(id)) { - return (Some(selection), visited); - } - - if id == rustc_hir::CRATE_HIR_ID { - current = None; - } else { - current = Some(cx.tcx.parent_hir_id(id)); - } - } - - (None, visited) - } -} - -fn profiles_from_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) -> Option { - let mut entries = SmallVec::<[ProfileEntry; 2]>::new(); - - for attr in attrs { - let path = attr.path(); - if path.len() != 2 || path[0] != sym::clippy { - continue; - } - - let name = path[1]; - if name != sym::disallowed_profile && name != sym::disallowed_profiles { - continue; - } - - let attr_label = if name == sym::disallowed_profiles { - "`clippy::disallowed_profiles`" - } else { - "`clippy::disallowed_profile`" - }; - - let Some(items) = attr.meta_item_list() else { - cx.tcx - .sess - .dcx() - .struct_span_err(attr.span(), format!("{attr_label} expects string arguments")) - .emit(); - continue; - }; - - if items.is_empty() { - cx.tcx - .sess - .dcx() - .struct_span_err(attr.span(), format!("{attr_label} expects at least one profile name")) - .emit(); - continue; - } - - if name == sym::disallowed_profile && items.len() != 1 { - cx.tcx - .sess - .dcx() - .struct_span_err(attr.span(), "use `clippy::disallowed_profiles` for multiple profiles") - .emit(); - } - - for item in items { - match literal_symbol(&item) { - Some((symbol, span)) => entries.push(ProfileEntry { - attr_name: name, - name: symbol, - span, - }), - None => emit_string_error(cx, &item), - } - } - } - - if entries.is_empty() { - None - } else { - Some(ProfileSelection::new(entries)) - } -} - -fn literal_symbol(item: &MetaItemInner) -> Option<(Symbol, Span)> { - match item { - MetaItemInner::Lit(lit) => { - let LitKind::Str(symbol, _) = lit.kind else { return None }; - Some((symbol, lit.span)) - }, - MetaItemInner::MetaItem(_) => None, - } -} - -fn emit_string_error(cx: &LateContext<'_>, item: &MetaItemInner) { - let span = match item { - MetaItemInner::Lit(lit) => lit.span, - MetaItemInner::MetaItem(meta) => meta.span, - }; - cx.tcx - .sess - .dcx() - .struct_span_err(span, "expected string literal profile name") - .emit(); -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a067e5559569..83acfb49e355 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -46,7 +46,6 @@ mod check_proc_macro; pub mod comparisons; pub mod consts; pub mod diagnostics; -pub mod disallowed_profiles; pub mod eager_or_lazy; pub mod higher; mod hir_utils; diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index f414c0ac47fa..fe8c62d3a0fa 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -208,8 +208,6 @@ generate! { deprecated_in_future, deref_mut_method, diagnostics, - disallowed_profile, - disallowed_profiles, disallowed_types, drain, dump, diff --git a/tests/ui-toml/disallowed_profiles_methods/clippy.toml b/tests/ui-toml/disallowed_profiles_methods/clippy.toml deleted file mode 100644 index c77f5658ae69..000000000000 --- a/tests/ui-toml/disallowed_profiles_methods/clippy.toml +++ /dev/null @@ -1,13 +0,0 @@ -disallowed-methods = [ - { path = "std::mem::drop" } -] - -[profiles.forward_pass] -disallowed-methods = [ - { path = "alloc::vec::Vec::push", reason = "push is forbidden in forward profile" } -] - -[profiles.export] -disallowed-methods = [ - { path = "core::option::Option::unwrap" } -] diff --git a/tests/ui-toml/disallowed_profiles_methods/main.rs b/tests/ui-toml/disallowed_profiles_methods/main.rs deleted file mode 100644 index 07bb22e05d6f..000000000000 --- a/tests/ui-toml/disallowed_profiles_methods/main.rs +++ /dev/null @@ -1,78 +0,0 @@ -#![warn(clippy::disallowed_methods)] -#![allow( - unused, - clippy::no_effect, - clippy::needless_borrow, - clippy::vec_init_then_push, - clippy::unnecessary_literal_unwrap -)] - -fn default_violation() { - let value = String::from("test"); - std::mem::drop(value); //~ ERROR: use of a disallowed method `std::mem::drop` -} - -#[expect(clippy::disallowed_methods)] -fn expected_violation() { - let value = String::from("test"); - std::mem::drop(value); -} - -#[clippy::disallowed_profile("forward_pass")] -fn forward_profile() { - let mut values = Vec::new(); - values.push(1); //~ ERROR: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) -} - -#[clippy::disallowed_profile("export")] -fn export_profile() { - let value = Some(1); - value.unwrap(); //~ ERROR: use of a disallowed method `core::option::Option::unwrap` (profile: export) -} - -#[clippy::disallowed_profile("unknown_profile")] -//~^ ERROR: unknown profile `unknown_profile` for -//~| ERROR: unknown profile `unknown_profile` for -fn unknown_profile() { - let mut values = Vec::new(); - values.push(1); - // unknown profile falls back to the default list - std::mem::drop(values); //~ ERROR: use of a disallowed method `std::mem::drop` -} - -#[clippy::disallowed_profiles("forward_pass", "export")] -fn merged_profiles() { - let mut values = Vec::new(); - values.push(1); //~ ERROR: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) - let value = Some(1); - value.unwrap(); //~ ERROR: use of a disallowed method `core::option::Option::unwrap` (profile: export) -} - -// `#[expect(clippy::disallowed_methods)]` silences the body warning and the unknown-profile -// warning tagged under `DISALLOWED_METHODS`, but not the one tagged under `DISALLOWED_TYPES`. -#[expect(clippy::disallowed_methods)] -#[clippy::disallowed_profile("unknown_profile_expect_before")] -//~^ ERROR: unknown profile `unknown_profile_expect_before` for `clippy::disallowed_types` -fn expect_before_unknown_profile() { - let value = String::from("test"); - std::mem::drop(value); -} - -#[clippy::disallowed_profile("unknown_profile_expect_after")] -//~^ ERROR: unknown profile `unknown_profile_expect_after` for `clippy::disallowed_types` -#[expect(clippy::disallowed_methods)] -fn expect_after_unknown_profile() { - let value = String::from("test"); - std::mem::drop(value); -} - -fn main() { - default_violation(); - expected_violation(); - forward_profile(); - export_profile(); - unknown_profile(); - merged_profiles(); - expect_before_unknown_profile(); - expect_after_unknown_profile(); -} diff --git a/tests/ui-toml/disallowed_profiles_methods/main.stderr b/tests/ui-toml/disallowed_profiles_methods/main.stderr deleted file mode 100644 index 5f64b1bf4499..000000000000 --- a/tests/ui-toml/disallowed_profiles_methods/main.stderr +++ /dev/null @@ -1,72 +0,0 @@ -error: use of a disallowed method `std::mem::drop` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:12:5 - | -LL | std::mem::drop(value); - | ^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-methods` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` - -error: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) - --> tests/ui-toml/disallowed_profiles_methods/main.rs:24:12 - | -LL | values.push(1); - | ^^^^ - | - = note: push is forbidden in forward profile - -error: use of a disallowed method `core::option::Option::unwrap` (profile: export) - --> tests/ui-toml/disallowed_profiles_methods/main.rs:30:11 - | -LL | value.unwrap(); - | ^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_profile` for `clippy::disallowed_methods` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:33:30 - | -LL | #[clippy::disallowed_profile("unknown_profile")] - | ^^^^^^^^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_profile` for `clippy::disallowed_types` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:33:30 - | -LL | #[clippy::disallowed_profile("unknown_profile")] - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-types` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` - -error: use of a disallowed method `std::mem::drop` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:40:5 - | -LL | std::mem::drop(values); - | ^^^^^^^^^^^^^^ - -error: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) - --> tests/ui-toml/disallowed_profiles_methods/main.rs:46:12 - | -LL | values.push(1); - | ^^^^ - | - = note: push is forbidden in forward profile - -error: use of a disallowed method `core::option::Option::unwrap` (profile: export) - --> tests/ui-toml/disallowed_profiles_methods/main.rs:48:11 - | -LL | value.unwrap(); - | ^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_profile_expect_before` for `clippy::disallowed_types` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:54:30 - | -LL | #[clippy::disallowed_profile("unknown_profile_expect_before")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_profile_expect_after` for `clippy::disallowed_types` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:61:30 - | -LL | #[clippy::disallowed_profile("unknown_profile_expect_after")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 10 previous errors - diff --git a/tests/ui-toml/disallowed_profiles_types/clippy.toml b/tests/ui-toml/disallowed_profiles_types/clippy.toml deleted file mode 100644 index 3c47b2afe26f..000000000000 --- a/tests/ui-toml/disallowed_profiles_types/clippy.toml +++ /dev/null @@ -1,13 +0,0 @@ -disallowed-types = [ - { path = "std::rc::Rc" } -] - -[profiles.forward_pass] -disallowed-types = [ - { path = "std::cell::RefCell", reason = "Prefer shared references" } -] - -[profiles.export] -disallowed-types = [ - { path = "std::sync::Mutex" } -] diff --git a/tests/ui-toml/disallowed_profiles_types/main.rs b/tests/ui-toml/disallowed_profiles_types/main.rs deleted file mode 100644 index 0161417dd602..000000000000 --- a/tests/ui-toml/disallowed_profiles_types/main.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![warn(clippy::disallowed_types)] -#![allow(dead_code)] - -use std::rc::Rc; //~ ERROR: use of a disallowed type `std::rc::Rc` -use std::sync::Mutex; - -struct Wrapper; - -fn default_type() { - let _value: Rc = todo!(); //~ ERROR: use of a disallowed type `std::rc::Rc` -} - -#[clippy::disallowed_profile("forward_pass")] -fn forward_profile() { - let _value: std::cell::RefCell = todo!(); //~ ERROR: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) -} - -#[clippy::disallowed_profile("export")] -fn export_profile() { - let _value: Mutex = todo!(); //~ ERROR: use of a disallowed type `std::sync::Mutex` (profile: export) -} - -#[clippy::disallowed_profile("unknown_type_profile")] -//~^ ERROR: unknown profile `unknown_type_profile` for -//~| ERROR: unknown profile `unknown_type_profile` for -fn unknown_profile() { - let _other = 1u32; - let _fallback: Rc = todo!(); //~ ERROR: use of a disallowed type `std::rc::Rc` -} - -#[clippy::disallowed_profiles("forward_pass", "export")] -fn merged_profiles() { - let _value: std::cell::RefCell = todo!(); //~ ERROR: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) - let _other: Mutex = todo!(); //~ ERROR: use of a disallowed type `std::sync::Mutex` (profile: export) -} - -// `#[expect(clippy::disallowed_types)]` silences the body warning and the unknown-profile -// warning tagged under `DISALLOWED_TYPES`, but not one tagged under `DISALLOWED_METHODS`. -#[expect(clippy::disallowed_types)] -#[clippy::disallowed_profile("unknown_type_profile_expect_before")] -//~^ ERROR: unknown profile `unknown_type_profile_expect_before` for `clippy::disallowed_methods` -fn expect_before_unknown_profile() { - let _value: Rc = todo!(); -} - -#[clippy::disallowed_profile("unknown_type_profile_expect_after")] -//~^ ERROR: unknown profile `unknown_type_profile_expect_after` for `clippy::disallowed_methods` -#[expect(clippy::disallowed_types)] -fn expect_after_unknown_profile() { - let _value: Rc = todo!(); -} - -fn main() { - default_type(); - forward_profile(); - export_profile(); - unknown_profile(); - merged_profiles(); - expect_before_unknown_profile(); - expect_after_unknown_profile(); -} diff --git a/tests/ui-toml/disallowed_profiles_types/main.stderr b/tests/ui-toml/disallowed_profiles_types/main.stderr deleted file mode 100644 index 68d63e218c0d..000000000000 --- a/tests/ui-toml/disallowed_profiles_types/main.stderr +++ /dev/null @@ -1,78 +0,0 @@ -error: use of a disallowed type `std::rc::Rc` - --> tests/ui-toml/disallowed_profiles_types/main.rs:4:1 - | -LL | use std::rc::Rc; - | ^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-types` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` - -error: use of a disallowed type `std::rc::Rc` - --> tests/ui-toml/disallowed_profiles_types/main.rs:10:17 - | -LL | let _value: Rc = todo!(); - | ^^^^^^^ - -error: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) - --> tests/ui-toml/disallowed_profiles_types/main.rs:15:17 - | -LL | let _value: std::cell::RefCell = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: Prefer shared references - -error: use of a disallowed type `std::sync::Mutex` (profile: export) - --> tests/ui-toml/disallowed_profiles_types/main.rs:20:17 - | -LL | let _value: Mutex = todo!(); - | ^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile` for `clippy::disallowed_methods` - --> tests/ui-toml/disallowed_profiles_types/main.rs:23:30 - | -LL | #[clippy::disallowed_profile("unknown_type_profile")] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-methods` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` - -error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile` for `clippy::disallowed_types` - --> tests/ui-toml/disallowed_profiles_types/main.rs:23:30 - | -LL | #[clippy::disallowed_profile("unknown_type_profile")] - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: use of a disallowed type `std::rc::Rc` - --> tests/ui-toml/disallowed_profiles_types/main.rs:28:20 - | -LL | let _fallback: Rc = todo!(); - | ^^^^^^^ - -error: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) - --> tests/ui-toml/disallowed_profiles_types/main.rs:33:17 - | -LL | let _value: std::cell::RefCell = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: Prefer shared references - -error: use of a disallowed type `std::sync::Mutex` (profile: export) - --> tests/ui-toml/disallowed_profiles_types/main.rs:34:17 - | -LL | let _other: Mutex = todo!(); - | ^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile_expect_before` for `clippy::disallowed_methods` - --> tests/ui-toml/disallowed_profiles_types/main.rs:40:30 - | -LL | #[clippy::disallowed_profile("unknown_type_profile_expect_before")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile_expect_after` for `clippy::disallowed_methods` - --> tests/ui-toml/disallowed_profiles_types/main.rs:46:30 - | -LL | #[clippy::disallowed_profile("unknown_type_profile_expect_after")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 11 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 ba930d094fc1..6bb3db8db67f 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -70,7 +70,6 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect module-items-ordered-within-groupings msrv pass-by-value-size-limit - profiles pub-underscore-fields-behavior recursive-self-in-type-definitions semicolon-inside-block-ignore-singleline @@ -172,7 +171,6 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect module-items-ordered-within-groupings msrv pass-by-value-size-limit - profiles pub-underscore-fields-behavior recursive-self-in-type-definitions semicolon-inside-block-ignore-singleline @@ -274,7 +272,6 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni module-items-ordered-within-groupings msrv pass-by-value-size-limit - profiles pub-underscore-fields-behavior recursive-self-in-type-definitions semicolon-inside-block-ignore-singleline