1 use rustc_ast::{ast, attr};
2 use rustc_errors::Applicability;
3 use rustc_session::Session;
7 /// Deprecation status of attributes known by Clippy.
9 pub enum DeprecationStatus {
10 /// Attribute is deprecated
12 /// Attribute is deprecated and was replaced by the named attribute
13 Replaced(&'static str),
18 pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
19 ("author", DeprecationStatus::None),
20 ("version", DeprecationStatus::None),
21 ("cognitive_complexity", DeprecationStatus::None),
22 ("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")),
23 ("dump", DeprecationStatus::None),
24 ("msrv", DeprecationStatus::None),
27 pub struct LimitStack {
31 impl Drop for LimitStack {
33 assert_eq!(self.stack.len(), 1);
39 pub fn new(limit: u64) -> Self {
40 Self { stack: vec![limit] }
42 pub fn limit(&self) -> u64 {
43 *self.stack.last().expect("there should always be a value in the stack")
45 pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
46 let stack = &mut self.stack;
47 parse_attrs(sess, attrs, name, |val| stack.push(val));
49 pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
50 let stack = &mut self.stack;
51 parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
57 attrs: &'a [ast::Attribute],
59 ) -> impl Iterator<Item = &'a ast::Attribute> {
60 attrs.iter().filter(move |attr| {
61 let attr = if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
66 let attr_segments = &attr.path.segments;
67 if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy {
70 .find_map(|&(builtin_name, ref deprecation_status)| {
71 if attr_segments[1].ident.name.as_str() == builtin_name {
72 Some(deprecation_status)
79 sess.span_err(attr_segments[1].ident.span, "usage of unknown attribute");
82 |deprecation_status| {
84 sess.struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
85 match *deprecation_status {
86 DeprecationStatus::Deprecated => {
90 DeprecationStatus::Replaced(new_name) => {
92 attr_segments[1].ident.span,
95 Applicability::MachineApplicable,
100 DeprecationStatus::None => {
102 attr_segments[1].ident.name.as_str() == name
113 fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) {
114 for attr in get_attr(sess, attrs, name) {
115 if let Some(ref value) = attr.value_str() {
116 if let Ok(value) = FromStr::from_str(value.as_str()) {
119 sess.span_err(attr.span, "not a number");
122 sess.span_err(attr.span, "bad clippy attribute");
127 pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'static str) -> Option<ast::Attribute> {
128 let mut unique_attr = None;
129 for attr in get_attr(sess, attrs, name) {
131 ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()),
132 ast::AttrStyle::Inner => {
133 sess.struct_span_err(attr.span, &format!("`{}` is defined multiple times", name))
134 .span_note(unique_attr.as_ref().unwrap().span, "first definition found here")
137 ast::AttrStyle::Outer => {
138 sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name));
145 /// Return true if the attributes contain any of `proc_macro`,
146 /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
147 pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
148 attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
151 /// Return true if the attributes contain `#[doc(hidden)]`
152 pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
155 .filter(|attr| attr.has_name(sym::doc))
156 .filter_map(ast::Attribute::meta_item_list)
157 .any(|l| attr::list_contains_name(&l, sym::hidden))
160 /// Return true if the attributes contain `#[unstable]`
161 pub fn is_unstable(attrs: &[ast::Attribute]) -> bool {
162 attrs.iter().any(|attr| attr.has_name(sym::unstable))