From 56b1a0f8e3ee0022a1c0c44d828ca58f2cceb7cf Mon Sep 17 00:00:00 2001 From: David Baumgarten Date: Wed, 19 Jun 2024 10:16:01 -0500 Subject: [PATCH 1/3] remove duplicate diags for deprecated attributes --- clippy_utils/Cargo.toml | 2 + clippy_utils/src/attrs.rs | 110 +++++++++++++++++++++------ tests/ui/renamed_builtin_attr.fixed | 1 - tests/ui/renamed_builtin_attr.rs | 1 - tests/ui/renamed_builtin_attr.stderr | 2 +- 5 files changed, 89 insertions(+), 27 deletions(-) diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 3a3aeb882164..4d62c146793a 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -9,6 +9,8 @@ clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } itertools = "0.12" rustc-semver = "1.1" +rustc-hash = "1.1" +lazy_static = "1.4" [features] deny-warnings = ["clippy_config/deny-warnings"] diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index d2200bcf7103..00e4e961535e 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -6,10 +6,48 @@ use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; use rustc_span::{sym, Span}; use std::str::FromStr; +use lazy_static::lazy_static; +use rustc_hash::FxHashSet; +use std::sync::RwLock; + +use std::io::{self, Write}; + use crate::source::snippet_opt; use crate::tokenize_with_text; + +pub struct EmissionState { + emitted: RwLock>, +} + +impl EmissionState { + pub fn new() -> Self { + Self { + emitted: RwLock::new(FxHashSet::default()), + } + } + + pub fn has_emitted(&self, attr_name: &str) -> bool { + let emitted = self.emitted.read().unwrap(); + emitted.contains(attr_name) + } + + pub fn set_emitted(&self, attr_name: &str) { + let mut emitted = self.emitted.write().unwrap(); + emitted.insert(attr_name.to_string()); + } + + pub fn reset(&self) { + let mut emitted = self.emitted.write().unwrap(); + emitted.clear(); + } +} + +lazy_static! { + pub static ref GLOBAL_EMISSION_STATE: EmissionState = EmissionState::new(); +} + /// Deprecation status of attributes known by Clippy. pub enum DeprecationStatus { /// Attribute is deprecated @@ -58,6 +96,8 @@ impl LimitStack { } } + + pub fn get_attr<'a>( sess: &'a Session, attrs: &'a [ast::Attribute], @@ -69,8 +109,15 @@ pub fn get_attr<'a>( } else { return false; }; + + let attr_segments = &attr.path.segments; - if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy { + + + if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy { + let attr_name = attr_segments[1].ident.name.as_str().to_string(); + + BUILTIN_ATTRIBUTES .iter() .find_map(|&(builtin_name, ref deprecation_status)| { @@ -82,36 +129,51 @@ pub fn get_attr<'a>( }) .map_or_else( || { + sess.dcx() .span_err(attr_segments[1].ident.span, "usage of unknown attribute"); false }, |deprecation_status| { - let mut diag = sess - .dcx() - .struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute"); - match *deprecation_status { - DeprecationStatus::Deprecated => { - diag.emit(); - false - }, - DeprecationStatus::Replaced(new_name) => { - diag.span_suggestion( - attr_segments[1].ident.span, - "consider using", - new_name, - Applicability::MachineApplicable, - ); - diag.emit(); - false - }, - DeprecationStatus::None => { - diag.cancel(); - attr_segments[1].ident.name.as_str() == name - }, + + if !GLOBAL_EMISSION_STATE.has_emitted(&attr_name) { + let mut diag = sess + .dcx() + .struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute"); + + match *deprecation_status { + DeprecationStatus::Deprecated => { + GLOBAL_EMISSION_STATE.set_emitted(&attr_name); + diag.emit(); + + io::stderr().flush().unwrap(); // Flush stderr + false + }, + DeprecationStatus::Replaced(new_name) => { + GLOBAL_EMISSION_STATE.set_emitted(&attr_name); + diag.span_suggestion( + attr_segments[1].ident.span, + "consider using", + new_name, + Applicability::MachineApplicable, + ); + diag.emit(); + + io::stderr().flush().unwrap(); // Flush stderr + false + }, + DeprecationStatus::None => { + diag.cancel(); + attr_segments[1].ident.name.as_str() == name + }, + } + } else { + false } }, - ) + + ) + } else { false } diff --git a/tests/ui/renamed_builtin_attr.fixed b/tests/ui/renamed_builtin_attr.fixed index aebf8712dd92..3c25c95a292a 100644 --- a/tests/ui/renamed_builtin_attr.fixed +++ b/tests/ui/renamed_builtin_attr.fixed @@ -1,4 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes #[clippy::cognitive_complexity = "1"] fn main() {} diff --git a/tests/ui/renamed_builtin_attr.rs b/tests/ui/renamed_builtin_attr.rs index 6c18151195f5..08e22eda05b4 100644 --- a/tests/ui/renamed_builtin_attr.rs +++ b/tests/ui/renamed_builtin_attr.rs @@ -1,4 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes #[clippy::cyclomatic_complexity = "1"] fn main() {} diff --git a/tests/ui/renamed_builtin_attr.stderr b/tests/ui/renamed_builtin_attr.stderr index fb51313dab69..53b901484768 100644 --- a/tests/ui/renamed_builtin_attr.stderr +++ b/tests/ui/renamed_builtin_attr.stderr @@ -1,5 +1,5 @@ error: usage of deprecated attribute - --> tests/ui/renamed_builtin_attr.rs:3:11 + --> tests/ui/renamed_builtin_attr.rs:2:11 | LL | #[clippy::cyclomatic_complexity = "1"] | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity` From 4ed533dd6561638e1ab5493847508c2370b15d14 Mon Sep 17 00:00:00 2001 From: David Baumgarten Date: Wed, 19 Jun 2024 12:32:18 -0500 Subject: [PATCH 2/3] update formatting --- clippy_utils/src/attrs.rs | 25 +++++++------------------ tests/ui/renamed_builtin_attr.fixed | 1 - tests/ui/renamed_builtin_attr.rs | 1 - tests/ui/renamed_builtin_attr.stderr | 2 +- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 00e4e961535e..7e0b48b9cf18 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -1,22 +1,20 @@ +use lazy_static::lazy_static; use rustc_ast::{ast, attr}; use rustc_errors::Applicability; +use rustc_hash::FxHashSet; use rustc_lexer::TokenKind; use rustc_lint::LateContext; use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; use rustc_span::{sym, Span}; use std::str::FromStr; -use lazy_static::lazy_static; -use rustc_hash::FxHashSet; use std::sync::RwLock; use std::io::{self, Write}; - use crate::source::snippet_opt; use crate::tokenize_with_text; - pub struct EmissionState { emitted: RwLock>, } @@ -96,8 +94,6 @@ impl LimitStack { } } - - pub fn get_attr<'a>( sess: &'a Session, attrs: &'a [ast::Attribute], @@ -110,13 +106,10 @@ pub fn get_attr<'a>( return false; }; - let attr_segments = &attr.path.segments; - - if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy { + if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy { let attr_name = attr_segments[1].ident.name.as_str().to_string(); - BUILTIN_ATTRIBUTES .iter() @@ -129,23 +122,21 @@ pub fn get_attr<'a>( }) .map_or_else( || { - sess.dcx() .span_err(attr_segments[1].ident.span, "usage of unknown attribute"); false }, |deprecation_status| { - if !GLOBAL_EMISSION_STATE.has_emitted(&attr_name) { let mut diag = sess .dcx() .struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute"); - + match *deprecation_status { DeprecationStatus::Deprecated => { GLOBAL_EMISSION_STATE.set_emitted(&attr_name); diag.emit(); - + io::stderr().flush().unwrap(); // Flush stderr false }, @@ -158,7 +149,7 @@ pub fn get_attr<'a>( Applicability::MachineApplicable, ); diag.emit(); - + io::stderr().flush().unwrap(); // Flush stderr false }, @@ -171,9 +162,7 @@ pub fn get_attr<'a>( false } }, - - ) - + ) } else { false } diff --git a/tests/ui/renamed_builtin_attr.fixed b/tests/ui/renamed_builtin_attr.fixed index 3c25c95a292a..bc055215708f 100644 --- a/tests/ui/renamed_builtin_attr.fixed +++ b/tests/ui/renamed_builtin_attr.fixed @@ -1,3 +1,2 @@ - #[clippy::cognitive_complexity = "1"] fn main() {} diff --git a/tests/ui/renamed_builtin_attr.rs b/tests/ui/renamed_builtin_attr.rs index 08e22eda05b4..fdb425363e81 100644 --- a/tests/ui/renamed_builtin_attr.rs +++ b/tests/ui/renamed_builtin_attr.rs @@ -1,3 +1,2 @@ - #[clippy::cyclomatic_complexity = "1"] fn main() {} diff --git a/tests/ui/renamed_builtin_attr.stderr b/tests/ui/renamed_builtin_attr.stderr index 53b901484768..f9108d169c71 100644 --- a/tests/ui/renamed_builtin_attr.stderr +++ b/tests/ui/renamed_builtin_attr.stderr @@ -1,5 +1,5 @@ error: usage of deprecated attribute - --> tests/ui/renamed_builtin_attr.rs:2:11 + --> tests/ui/renamed_builtin_attr.rs:1:11 | LL | #[clippy::cyclomatic_complexity = "1"] | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity` From 15f49e63dc4405db0a57da79eae3ee7d0c52f754 Mon Sep 17 00:00:00 2001 From: David Baumgarten Date: Wed, 19 Jun 2024 12:51:41 -0500 Subject: [PATCH 3/3] clean up code and add default implementation --- clippy_utils/src/attrs.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 7e0b48b9cf18..15b7f6b61dbe 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -42,6 +42,12 @@ impl EmissionState { } } +impl Default for EmissionState { + fn default() -> Self { + Self::new() + } +} + lazy_static! { pub static ref GLOBAL_EMISSION_STATE: EmissionState = EmissionState::new(); } @@ -127,7 +133,9 @@ pub fn get_attr<'a>( false }, |deprecation_status| { - if !GLOBAL_EMISSION_STATE.has_emitted(&attr_name) { + if GLOBAL_EMISSION_STATE.has_emitted(&attr_name) { + false + } else { let mut diag = sess .dcx() .struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute"); @@ -158,8 +166,6 @@ pub fn get_attr<'a>( attr_segments[1].ident.name.as_str() == name }, } - } else { - false } }, )