//! 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> { 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> { self.hir_docs(db).map(Cow::Borrowed) } fn resolve_doc_path( self, db: &dyn HirDatabase, link: &str, ns: Option, is_inner_doc: hir::IsInnerDoc, ) -> Option { 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> { 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> { 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)) } } } }