bon_macros/util/
attrs.rs

1use syn::spanned::Spanned;
2
3pub(crate) trait AttributeExt {
4    fn is_doc_expr(&self) -> bool;
5    fn as_doc_expr(&self) -> Option<&syn::Expr>;
6    fn to_allow(&self) -> Option<syn::Attribute>;
7}
8
9impl AttributeExt for syn::Attribute {
10    fn is_doc_expr(&self) -> bool {
11        self.as_doc_expr().is_some()
12    }
13
14    fn as_doc_expr(&self) -> Option<&syn::Expr> {
15        let attr = match &self.meta {
16            syn::Meta::NameValue(attr) => attr,
17            _ => return None,
18        };
19
20        if !attr.path.is_ident("doc") {
21            return None;
22        }
23
24        Some(&attr.value)
25    }
26
27    /// Returns `Some` if this is an `#[allow(...)]` or `#[expect(...)]` attribute.
28    /// Turns an `#[expect(...)]` into `#[allow(...)]`, which is useful to make sure
29    /// that macro doesn't trigger another warning that there is actually no
30    /// instance of a lint warning under the `#[expect(...)]`.
31    fn to_allow(&self) -> Option<syn::Attribute> {
32        if self.path().is_ident("allow") {
33            return Some(self.clone());
34        }
35
36        if !self.path().is_ident("expect") {
37            return None;
38        }
39
40        // Turn an `expect` into allow
41        let mut attr = self.clone();
42        let path = match &mut attr.meta {
43            syn::Meta::Path(path) => path,
44            syn::Meta::List(meta) => &mut meta.path,
45            syn::Meta::NameValue(meta) => &mut meta.path,
46        };
47
48        *path = syn::parse_quote_spanned!(path.span()=> allow);
49
50        Some(attr)
51    }
52}