1use super::SpannedKey;
2use crate::util::prelude::*;
34pub(crate) fn parse_docs_without_self_mentions(
5 context: &'static str,
6 meta: &syn::Meta,
7) -> Result<SpannedKey<Vec<syn::Attribute>>> {
8let docs = parse_docs(meta)?;
9 reject_self_mentions_in_docs(context, &docs)?;
10Ok(docs)
11}
1213pub(crate) fn parse_docs(meta: &syn::Meta) -> Result<SpannedKey<Vec<syn::Attribute>>> {
14let meta = meta.require_list()?;
1516 meta.require_curly_braces_delim()?;
1718let attrs = meta.parse_args_with(syn::Attribute::parse_outer)?;
1920for attr in &attrs {
21if !attr.is_doc_expr() {
22bail!(attr, "expected a doc comment");
23 }
24 }
2526 SpannedKey::new(&meta.path, attrs)
27}
2829/// 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 {
37for attr in attrs {
38let doc = match attr.as_doc_expr() {
39Some(doc) => doc,
40_ => continue,
41 };
4243let doc = match &doc {
44 syn::Expr::Lit(doc) => doc,
45_ => continue,
46 };
4748let doc = match &doc.lit {
49 syn::Lit::Str(doc) => doc,
50_ => continue,
51 };
5253let self_references = ["[`Self`]", "[Self]"];
5455if self_references
56 .iter()
57 .any(|self_ref| doc.value().contains(self_ref))
58 {
59bail!(
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 }
6768Ok(())
69}