bon_macros/parsing/
docs.rs

1use super::SpannedKey;
2use crate::util::prelude::*;
3
4pub(crate) fn parse_docs_without_self_mentions(
5    context: &'static str,
6    meta: &syn::Meta,
7) -> Result<SpannedKey<Vec<syn::Attribute>>> {
8    let docs = parse_docs(meta)?;
9    reject_self_mentions_in_docs(context, &docs)?;
10    Ok(docs)
11}
12
13pub(crate) fn parse_docs(meta: &syn::Meta) -> Result<SpannedKey<Vec<syn::Attribute>>> {
14    let meta = meta.require_list()?;
15
16    meta.require_curly_braces_delim()?;
17
18    let attrs = meta.parse_args_with(syn::Attribute::parse_outer)?;
19
20    for attr in &attrs {
21        if !attr.is_doc_expr() {
22            bail!(attr, "expected a doc comment");
23        }
24    }
25
26    SpannedKey::new(&meta.path, attrs)
27}
28
29/// Validates the docs for the presence of `Self` mentions to prevent users from
30/// shooting themselves in the foot where they would think that `Self` resolves
31/// to the current item the docs were placed on, when in fact the docs are moved
32/// to a different context where `Self` has a different meaning.
33pub(crate) fn reject_self_mentions_in_docs(
34    context: &'static str,
35    attrs: &[syn::Attribute],
36) -> Result {
37    for attr in attrs {
38        let doc = match attr.as_doc_expr() {
39            Some(doc) => doc,
40            _ => continue,
41        };
42
43        let doc = match &doc {
44            syn::Expr::Lit(doc) => doc,
45            _ => continue,
46        };
47
48        let doc = match &doc.lit {
49            syn::Lit::Str(doc) => doc,
50            _ => continue,
51        };
52
53        let self_references = ["[`Self`]", "[Self]"];
54
55        if self_references
56            .iter()
57            .any(|self_ref| doc.value().contains(self_ref))
58        {
59            bail!(
60                &doc.span(),
61                "the documentation should not reference `Self` because it will \
62                be moved to the {context} where `Self` changes meaning, which \
63                may confuse the reader of this code; use explicit type names instead.",
64            );
65        }
66    }
67
68    Ok(())
69}