2022-04-26 07:04:23 -05:00
|
|
|
use rustc_ast::ast;
|
2022-05-21 06:24:00 -05:00
|
|
|
use rustc_ast::attr;
|
2019-02-28 09:44:42 -06:00
|
|
|
use rustc_errors::Applicability;
|
2020-03-18 17:45:02 -05:00
|
|
|
use rustc_session::Session;
|
2021-01-15 03:56:44 -06:00
|
|
|
use rustc_span::sym;
|
2019-02-28 09:44:42 -06:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
/// Deprecation status of attributes known by Clippy.
|
|
|
|
pub enum DeprecationStatus {
|
|
|
|
/// Attribute is deprecated
|
|
|
|
Deprecated,
|
|
|
|
/// Attribute is deprecated and was replaced by the named attribute
|
|
|
|
Replaced(&'static str),
|
|
|
|
None,
|
|
|
|
}
|
|
|
|
|
2021-12-06 05:33:31 -06:00
|
|
|
#[rustfmt::skip]
|
2019-02-28 09:44:42 -06:00
|
|
|
pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
|
2021-12-06 05:33:31 -06:00
|
|
|
("author", DeprecationStatus::None),
|
|
|
|
("version", DeprecationStatus::None),
|
|
|
|
("cognitive_complexity", DeprecationStatus::None),
|
|
|
|
("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")),
|
|
|
|
("dump", DeprecationStatus::None),
|
|
|
|
("msrv", DeprecationStatus::None),
|
2022-02-18 00:02:22 -06:00
|
|
|
("has_significant_drop", DeprecationStatus::None),
|
2019-02-28 09:44:42 -06:00
|
|
|
];
|
|
|
|
|
|
|
|
pub struct LimitStack {
|
|
|
|
stack: Vec<u64>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for LimitStack {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
assert_eq!(self.stack.len(), 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LimitStack {
|
2019-09-18 01:37:41 -05:00
|
|
|
#[must_use]
|
2019-02-28 09:44:42 -06:00
|
|
|
pub fn new(limit: u64) -> Self {
|
|
|
|
Self { stack: vec![limit] }
|
|
|
|
}
|
|
|
|
pub fn limit(&self) -> u64 {
|
|
|
|
*self.stack.last().expect("there should always be a value in the stack")
|
|
|
|
}
|
|
|
|
pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
|
|
|
|
let stack = &mut self.stack;
|
|
|
|
parse_attrs(sess, attrs, name, |val| stack.push(val));
|
|
|
|
}
|
|
|
|
pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
|
|
|
|
let stack = &mut self.stack;
|
|
|
|
parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_attr<'a>(
|
|
|
|
sess: &'a Session,
|
|
|
|
attrs: &'a [ast::Attribute],
|
|
|
|
name: &'static str,
|
|
|
|
) -> impl Iterator<Item = &'a ast::Attribute> {
|
|
|
|
attrs.iter().filter(move |attr| {
|
2020-11-05 11:27:48 -06:00
|
|
|
let attr = if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
|
2019-11-07 02:34:45 -06:00
|
|
|
attr
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
};
|
2019-02-28 09:44:42 -06:00
|
|
|
let attr_segments = &attr.path.segments;
|
2021-01-15 03:56:44 -06:00
|
|
|
if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy {
|
2020-07-14 07:59:59 -05:00
|
|
|
BUILTIN_ATTRIBUTES
|
|
|
|
.iter()
|
2021-01-15 03:56:44 -06:00
|
|
|
.find_map(|&(builtin_name, ref deprecation_status)| {
|
|
|
|
if attr_segments[1].ident.name.as_str() == builtin_name {
|
2020-07-14 07:59:59 -05:00
|
|
|
Some(deprecation_status)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.map_or_else(
|
|
|
|
|| {
|
2020-08-11 08:43:21 -05:00
|
|
|
sess.span_err(attr_segments[1].ident.span, "usage of unknown attribute");
|
2019-02-28 09:44:42 -06:00
|
|
|
false
|
|
|
|
},
|
2020-07-14 07:59:59 -05:00
|
|
|
|deprecation_status| {
|
|
|
|
let mut diag =
|
2020-08-11 08:43:21 -05:00
|
|
|
sess.struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
|
2020-07-14 07:59:59 -05:00
|
|
|
match *deprecation_status {
|
|
|
|
DeprecationStatus::Deprecated => {
|
|
|
|
diag.emit();
|
|
|
|
false
|
|
|
|
},
|
|
|
|
DeprecationStatus::Replaced(new_name) => {
|
|
|
|
diag.span_suggestion(
|
|
|
|
attr_segments[1].ident.span,
|
|
|
|
"consider using",
|
2022-06-13 01:48:40 -05:00
|
|
|
new_name,
|
2020-07-14 07:59:59 -05:00
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
diag.emit();
|
|
|
|
false
|
|
|
|
},
|
|
|
|
DeprecationStatus::None => {
|
|
|
|
diag.cancel();
|
2021-01-15 03:56:44 -06:00
|
|
|
attr_segments[1].ident.name.as_str() == name
|
2020-07-14 07:59:59 -05:00
|
|
|
},
|
|
|
|
}
|
2019-02-28 09:44:42 -06:00
|
|
|
},
|
2020-07-14 07:59:59 -05:00
|
|
|
)
|
2019-02-28 09:44:42 -06:00
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) {
|
|
|
|
for attr in get_attr(sess, attrs, name) {
|
|
|
|
if let Some(ref value) = attr.value_str() {
|
2021-12-14 21:39:23 -06:00
|
|
|
if let Ok(value) = FromStr::from_str(value.as_str()) {
|
2021-06-03 01:41:37 -05:00
|
|
|
f(value);
|
2019-02-28 09:44:42 -06:00
|
|
|
} else {
|
|
|
|
sess.span_err(attr.span, "not a number");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sess.span_err(attr.span, "bad clippy attribute");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-18 08:54:25 -05:00
|
|
|
|
2020-12-06 08:01:03 -06:00
|
|
|
pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'static str) -> Option<ast::Attribute> {
|
|
|
|
let mut unique_attr = None;
|
|
|
|
for attr in get_attr(sess, attrs, name) {
|
|
|
|
match attr.style {
|
|
|
|
ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()),
|
|
|
|
ast::AttrStyle::Inner => {
|
|
|
|
sess.struct_span_err(attr.span, &format!("`{}` is defined multiple times", name))
|
|
|
|
.span_note(unique_attr.as_ref().unwrap().span, "first definition found here")
|
|
|
|
.emit();
|
|
|
|
},
|
|
|
|
ast::AttrStyle::Outer => {
|
|
|
|
sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unique_attr
|
|
|
|
}
|
|
|
|
|
2019-10-18 08:54:25 -05:00
|
|
|
/// Return true if the attributes contain any of `proc_macro`,
|
|
|
|
/// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
|
2020-07-29 20:27:50 -05:00
|
|
|
pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
|
|
|
|
attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
|
2019-10-18 08:54:25 -05:00
|
|
|
}
|
2021-04-08 10:50:13 -05:00
|
|
|
|
|
|
|
/// Return true if the attributes contain `#[doc(hidden)]`
|
|
|
|
pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
|
|
|
|
attrs
|
|
|
|
.iter()
|
|
|
|
.filter(|attr| attr.has_name(sym::doc))
|
2021-04-22 04:31:13 -05:00
|
|
|
.filter_map(ast::Attribute::meta_item_list)
|
2021-04-08 10:50:13 -05:00
|
|
|
.any(|l| attr::list_contains_name(&l, sym::hidden))
|
|
|
|
}
|