Unnamed repository; edit this file 'description' to name the repository.
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! Documentation attribute related utilities.
use std::borrow::Cow;

use hir::{HasAttrs, db::HirDatabase, resolve_doc_path_on};

/// Holds documentation
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Documentation<'db>(Cow<'db, str>);

impl<'db> Documentation<'db> {
    #[inline]
    pub fn new_owned(s: String) -> Self {
        Documentation(Cow::Owned(s))
    }

    #[inline]
    pub fn new_borrowed(s: &'db str) -> Self {
        Documentation(Cow::Borrowed(s))
    }

    #[inline]
    pub fn into_owned(self) -> Documentation<'static> {
        Documentation::new_owned(self.0.into_owned())
    }

    #[inline]
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

pub trait HasDocs: HasAttrs + Copy {
    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation<'_>> {
        let docs = match self.docs_with_rangemap(db)? {
            Cow::Borrowed(docs) => Documentation::new_borrowed(docs.docs()),
            Cow::Owned(docs) => Documentation::new_owned(docs.into_docs()),
        };
        Some(docs)
    }
    fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<Cow<'_, hir::Docs>> {
        self.hir_docs(db).map(Cow::Borrowed)
    }
    fn resolve_doc_path(
        self,
        db: &dyn HirDatabase,
        link: &str,
        ns: Option<hir::Namespace>,
        is_inner_doc: hir::IsInnerDoc,
    ) -> Option<hir::DocLinkDef> {
        resolve_doc_path_on(db, self, link, ns, is_inner_doc)
    }
}

macro_rules! impl_has_docs {
    ($($def:ident,)*) => {$(
        impl HasDocs for hir::$def {}
    )*};
}

impl_has_docs![
    Variant, Field, Static, Const, Trait, TypeAlias, Macro, Function, Adt, Module, Impl, Crate,
    AssocItem, Struct, Union, Enum,
];

impl HasDocs for hir::ExternCrateDecl {
    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation<'_>> {
        let crate_docs = self.resolved_crate(db)?.hir_docs(db);
        let decl_docs = self.hir_docs(db);
        match (decl_docs, crate_docs) {
            (None, None) => None,
            (Some(docs), None) | (None, Some(docs)) => {
                Some(Documentation::new_borrowed(docs.docs()))
            }
            (Some(decl_docs), Some(crate_docs)) => {
                let mut docs = String::with_capacity(
                    decl_docs.docs().len() + "\n\n".len() + crate_docs.docs().len(),
                );
                docs.push_str(decl_docs.docs());
                docs.push_str("\n\n");
                docs.push_str(crate_docs.docs());
                Some(Documentation::new_owned(docs))
            }
        }
    }

    fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<Cow<'_, hir::Docs>> {
        let crate_docs = self.resolved_crate(db)?.hir_docs(db);
        let decl_docs = self.hir_docs(db);
        match (decl_docs, crate_docs) {
            (None, None) => None,
            (Some(docs), None) | (None, Some(docs)) => Some(Cow::Borrowed(docs)),
            (Some(decl_docs), Some(crate_docs)) => {
                let mut docs = decl_docs.clone();
                docs.append_str("\n\n");
                docs.append(crate_docs);
                Some(Cow::Owned(docs))
            }
        }
    }
}