]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/utils/attrs.rs
Remove wrong lifetime from LintContext
[rust.git] / clippy_lints / src / utils / attrs.rs
1 use rustc::session::Session;
2 use rustc_errors::Applicability;
3 use std::str::FromStr;
4 use syntax::ast;
5
6 /// Deprecation status of attributes known by Clippy.
7 #[allow(dead_code)]
8 pub enum DeprecationStatus {
9     /// Attribute is deprecated
10     Deprecated,
11     /// Attribute is deprecated and was replaced by the named attribute
12     Replaced(&'static str),
13     None,
14 }
15
16 pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
17     ("author", DeprecationStatus::None),
18     ("cognitive_complexity", DeprecationStatus::None),
19     (
20         "cyclomatic_complexity",
21         DeprecationStatus::Replaced("cognitive_complexity"),
22     ),
23     ("dump", DeprecationStatus::None),
24 ];
25
26 pub struct LimitStack {
27     stack: Vec<u64>,
28 }
29
30 impl Drop for LimitStack {
31     fn drop(&mut self) {
32         assert_eq!(self.stack.len(), 1);
33     }
34 }
35
36 impl LimitStack {
37     pub fn new(limit: u64) -> Self {
38         Self { stack: vec![limit] }
39     }
40     pub fn limit(&self) -> u64 {
41         *self.stack.last().expect("there should always be a value in the stack")
42     }
43     pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
44         let stack = &mut self.stack;
45         parse_attrs(sess, attrs, name, |val| stack.push(val));
46     }
47     pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
48         let stack = &mut self.stack;
49         parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
50     }
51 }
52
53 pub fn get_attr<'a>(
54     sess: &'a Session,
55     attrs: &'a [ast::Attribute],
56     name: &'static str,
57 ) -> impl Iterator<Item = &'a ast::Attribute> {
58     attrs.iter().filter(move |attr| {
59         let attr_segments = &attr.path.segments;
60         if attr_segments.len() == 2 && attr_segments[0].ident.to_string() == "clippy" {
61             if let Some(deprecation_status) =
62                 BUILTIN_ATTRIBUTES
63                     .iter()
64                     .find_map(|(builtin_name, deprecation_status)| {
65                         if *builtin_name == attr_segments[1].ident.to_string() {
66                             Some(deprecation_status)
67                         } else {
68                             None
69                         }
70                     })
71             {
72                 let mut db = sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute");
73                 match deprecation_status {
74                     DeprecationStatus::Deprecated => {
75                         db.emit();
76                         false
77                     },
78                     DeprecationStatus::Replaced(new_name) => {
79                         db.span_suggestion(
80                             attr_segments[1].ident.span,
81                             "consider using",
82                             new_name.to_string(),
83                             Applicability::MachineApplicable,
84                         );
85                         db.emit();
86                         false
87                     },
88                     DeprecationStatus::None => {
89                         db.cancel();
90                         attr_segments[1].ident.to_string() == name
91                     },
92                 }
93             } else {
94                 sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute");
95                 false
96             }
97         } else {
98             false
99         }
100     })
101 }
102
103 fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) {
104     for attr in get_attr(sess, attrs, name) {
105         if let Some(ref value) = attr.value_str() {
106             if let Ok(value) = FromStr::from_str(&value.as_str()) {
107                 f(value)
108             } else {
109                 sess.span_err(attr.span, "not a number");
110             }
111         } else {
112             sess.span_err(attr.span, "bad clippy attribute");
113         }
114     }
115 }