Skip to main content

solar_ast/ast/
natspec.rs

1use super::BoxSlice;
2use crate::token::CommentKind;
3use solar_interface::{Ident, Span, Symbol};
4use std::fmt;
5
6/// A single doc-comment: `/// foo`, `/** bar */`.
7#[derive(Debug)]
8pub struct DocComment<'ast> {
9    /// The comment kind.
10    pub kind: CommentKind,
11    /// The comment's span including its "quotes" (`//`, `/**`).
12    pub span: Span,
13    /// The comment's contents excluding its "quotes" (`//`, `/**`)
14    /// similarly to symbols in string literal tokens.
15    pub symbol: Symbol,
16    /// The comment's natspec items
17    pub natspec: BoxSlice<'ast, NatSpecItem>,
18}
19
20impl<'ast> DocComment<'ast> {
21    /// Returns the content of a natspec excluding its tag.
22    pub fn natspec_content<'a>(&self, item: &'a NatSpecItem) -> &'a str {
23        item.content()
24    }
25}
26
27/// A single item within a Natspec comment block.
28#[derive(Clone, Copy, Debug)]
29pub struct NatSpecItem {
30    /// The tag identifier of the item.
31    pub kind: NatSpecKind,
32    /// Span of the tag. '@' is not included.
33    pub span: Span,
34    /// The symbol containing this tag's content.
35    pub symbol: Symbol,
36    /// Byte offset into the doc comment's symbol where this tag's content starts.
37    pub content_start: u32,
38    /// Byte offset into the doc comment's symbol where this tag's content ends.
39    pub content_end: u32,
40}
41
42impl NatSpecItem {
43    /// Returns the byte range of this item's content within the doc comment's symbol.
44    pub fn content_range(&self) -> std::ops::Range<usize> {
45        self.content_start as usize..self.content_end as usize
46    }
47
48    /// Returns the text content of this natspec item.
49    ///
50    /// The content is extracted from the symbol using the byte offsets.
51    pub fn content(&self) -> &str {
52        &self.symbol.as_str()[self.content_range()]
53    }
54}
55
56impl fmt::Display for NatSpecItem {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        let content = self.content();
59        match self.kind {
60            NatSpecKind::Title => write!(f, "@title {content}"),
61            NatSpecKind::Author => write!(f, "@author {content}"),
62            NatSpecKind::Notice => write!(f, "@notice {content}"),
63            NatSpecKind::Dev => write!(f, "@dev {content}"),
64            NatSpecKind::Param { name } => write!(f, "@param {} {content}", name.name),
65            NatSpecKind::Return { name: Some(name) } => {
66                write!(f, "@return {} {content}", name.name)
67            }
68            NatSpecKind::Return { name: None } => write!(f, "@return {content}"),
69            NatSpecKind::Inheritdoc { contract } => {
70                write!(f, "@inheritdoc {} {content}", contract.name)
71            }
72            NatSpecKind::Custom { name } => write!(f, "@custom:{} {content}", name.name),
73            NatSpecKind::Internal { tag } => write!(f, "@{} {content}", tag.name),
74        }
75    }
76}
77
78/// The kind of a [`NatSpecItem`].
79///
80/// Reference: <https://docs.soliditylang.org/en/latest/natspec-format.html#tags>
81#[derive(Clone, Copy, Debug, PartialEq, Eq)]
82pub enum NatSpecKind {
83    /// `@title`
84    ///
85    /// A title that describes the contract.
86    Title,
87    /// `@author`
88    ///
89    /// The name of the author.
90    Author,
91    /// `@notice`
92    ///
93    /// An annotation for end-users.
94    Notice,
95    /// `@dev`
96    ///
97    /// A technical annotation for developers.
98    Dev,
99    /// `@param <name>`
100    ///
101    /// Documents a parameter. The `name` field contains the parameter name.
102    Param { name: Ident },
103    /// `@return <name>`
104    ///
105    /// Documents a return variable. The optional `name` field contains the return variable name.
106    Return { name: Option<Ident> },
107    /// `@inheritdoc <contract>`
108    ///
109    /// Copies all tags from the base function. The `contract` field contains the contract name.
110    Inheritdoc { contract: Ident },
111    /// `@custom:<tag>`
112    ///
113    /// Custom tag with user-defined semantics. The `name` field contains the custom tag name.
114    Custom { name: Ident },
115
116    /// `@<tag>`
117    ///
118    /// Internal tags reserved for compiler purposes. The `tag` field contains the tag name.
119    Internal { tag: Ident },
120}
121
122/// Internal natspec tags.
123pub const NATSPEC_INTERNAL_TAGS: &[&str] = &["solidity", "src", "use-src", "ast-id"];