bon_macros/util/
attrs.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use syn::spanned::Spanned;

pub(crate) trait AttributeExt {
    fn is_doc_expr(&self) -> bool;
    fn as_doc_expr(&self) -> Option<&syn::Expr>;
    fn to_allow(&self) -> Option<syn::Attribute>;
}

impl AttributeExt for syn::Attribute {
    fn is_doc_expr(&self) -> bool {
        self.as_doc_expr().is_some()
    }

    fn as_doc_expr(&self) -> Option<&syn::Expr> {
        let attr = match &self.meta {
            syn::Meta::NameValue(attr) => attr,
            _ => return None,
        };

        if !attr.path.is_ident("doc") {
            return None;
        }

        Some(&attr.value)
    }

    /// Returns `Some` if this is an `#[allow(...)]` or `#[expect(...)]` attribute.
    /// Turns an `#[expect(...)]` into `#[allow(...)]`, which is useful to make sure
    /// that macro doesn't trigger another warning that there is actually no
    /// instance of a lint warning under the `#[expect(...)]`.
    fn to_allow(&self) -> Option<syn::Attribute> {
        if self.path().is_ident("allow") {
            return Some(self.clone());
        }

        if !self.path().is_ident("expect") {
            return None;
        }

        // Turn an `expect` into allow
        let mut attr = self.clone();
        let path = match &mut attr.meta {
            syn::Meta::Path(path) => path,
            syn::Meta::List(meta) => &mut meta.path,
            syn::Meta::NameValue(meta) => &mut meta.path,
        };

        *path = syn::parse_quote_spanned!(path.span()=> allow);

        Some(attr)
    }
}