use syn::{Meta, MetaList, Path, Token, ext::IdentExt, punctuated::Punctuated};
use super::Suppression;
pub(super) fn render_path(path: &Path) -> String {
path.segments
.iter()
.map(|segment| segment.ident.unraw().to_string())
.collect::<Vec<_>>()
.join("::")
}
fn allowed_lints(list: &MetaList) -> Vec<String> {
let Ok(nested) = list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated) else {
return Vec::new();
};
nested
.iter()
.filter_map(|meta| match meta {
Meta::Path(path) => Some(render_path(path)),
Meta::List(_) | Meta::NameValue(_) => None,
})
.collect()
}
fn suppressed_by_cfg_attr(list: &MetaList, inner: bool, sanctioned: bool) -> Vec<String> {
let Ok(nested) = list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated) else {
return Vec::new();
};
nested
.iter()
.skip(1)
.flat_map(|meta| suppressed_by(meta, inner, sanctioned))
.collect()
}
pub(super) fn suppressed_by(meta: &Meta, inner: bool, sanctioned: bool) -> Vec<String> {
let Ok(list) = meta.require_list() else {
return Vec::new();
};
match render_path(meta.path()).as_str() {
"allow" => allowed_lints(list),
"expect" if inner || !sanctioned => allowed_lints(list),
"cfg_attr" => suppressed_by_cfg_attr(list, inner, sanctioned),
_ => Vec::new(),
}
}
pub(super) fn render_attribute(suppression: &Suppression) -> String {
let bang = if suppression.inner { "!" } else { "" };
let path = render_path(suppression.meta.path());
suppression.meta.require_list().map_or_else(
|_| format!("#{bang}[{path}]"),
|list| format!("#{bang}[{path}({})]", list.tokens),
)
}