1use crate::priv_prelude::*;
2
3#[derive(Clone, Debug, Serialize)]
4pub struct Annotated<T> {
5 pub attributes: Vec<AttributeDecl>,
6 pub value: T,
7}
8
9pub const STORAGE_ATTRIBUTE_NAME: &str = "storage";
11pub const STORAGE_READ_ARG_NAME: &str = "read";
12pub const STORAGE_WRITE_ARG_NAME: &str = "write";
13
14pub const INLINE_ATTRIBUTE_NAME: &str = "inline";
16pub const INLINE_NEVER_ARG_NAME: &str = "never";
17pub const INLINE_ALWAYS_ARG_NAME: &str = "always";
18
19pub const PAYABLE_ATTRIBUTE_NAME: &str = "payable";
21
22pub const FALLBACK_ATTRIBUTE_NAME: &str = "fallback";
24
25pub const DOC_COMMENT_ATTRIBUTE_NAME: &str = "doc-comment";
31
32pub const TEST_ATTRIBUTE_NAME: &str = "test";
34pub const TEST_SHOULD_REVERT_ARG_NAME: &str = "should_revert";
35
36pub const ALLOW_ATTRIBUTE_NAME: &str = "allow";
38pub const ALLOW_DEAD_CODE_ARG_NAME: &str = "dead_code";
39pub const ALLOW_DEPRECATED_ARG_NAME: &str = "deprecated";
40
41pub const CFG_ATTRIBUTE_NAME: &str = "cfg";
43pub const CFG_TARGET_ARG_NAME: &str = "target";
44pub const CFG_PROGRAM_TYPE_ARG_NAME: &str = "program_type";
45
46pub const DEPRECATED_ATTRIBUTE_NAME: &str = "deprecated";
48pub const DEPRECATED_NOTE_ARG_NAME: &str = "note";
49
50pub const ERROR_TYPE_ATTRIBUTE_NAME: &str = "error_type";
52pub const ERROR_ATTRIBUTE_NAME: &str = "error";
53pub const ERROR_M_ARG_NAME: &str = "m";
54
55pub const KNOWN_ATTRIBUTE_NAMES: &[&str] = &[
56 STORAGE_ATTRIBUTE_NAME,
57 DOC_COMMENT_ATTRIBUTE_NAME,
58 TEST_ATTRIBUTE_NAME,
59 INLINE_ATTRIBUTE_NAME,
60 PAYABLE_ATTRIBUTE_NAME,
61 ALLOW_ATTRIBUTE_NAME,
62 CFG_ATTRIBUTE_NAME,
63 DEPRECATED_ATTRIBUTE_NAME,
64 FALLBACK_ATTRIBUTE_NAME,
65];
66
67#[derive(Clone, Debug, Serialize)]
89pub struct AttributeDecl {
90 pub hash_kind: AttributeHashKind,
91 pub attribute: SquareBrackets<Punctuated<Attribute, CommaToken>>,
92}
93
94impl AttributeDecl {
95 pub fn new_outer_doc_comment(span: Span, content_span: Span) -> Self {
102 Self::new_doc_comment(
103 span.clone(),
104 content_span,
105 AttributeHashKind::Outer(HashToken::new(span)),
106 )
107 }
108
109 pub fn new_inner_doc_comment(span: Span, content_span: Span) -> Self {
116 Self::new_doc_comment(
117 span.clone(),
118 content_span,
119 AttributeHashKind::Inner(HashBangToken::new(span)),
120 )
121 }
122
123 fn new_doc_comment(span: Span, content_span: Span, hash_kind: AttributeHashKind) -> Self {
124 let name = Ident::new_no_trim(content_span.clone());
127 AttributeDecl {
128 hash_kind,
129 attribute: SquareBrackets::new(
130 Punctuated::single(Attribute {
131 name: Ident::new_with_override(
132 DOC_COMMENT_ATTRIBUTE_NAME.to_string(),
133 span.clone(),
134 ),
135 args: Some(Parens::new(
136 Punctuated::single(AttributeArg { name, value: None }),
137 content_span,
138 )),
139 }),
140 span,
141 ),
142 }
143 }
144
145 pub fn is_doc_comment(&self) -> bool {
147 self.attribute.inner.value_separator_pairs.is_empty()
148 && self
149 .attribute
150 .inner
151 .final_value_opt
152 .as_ref()
153 .is_some_and(|attr| attr.is_doc_comment())
154 }
155
156 pub fn is_inner(&self) -> bool {
157 matches!(self.hash_kind, AttributeHashKind::Inner(_))
158 }
159}
160
161impl Spanned for AttributeDecl {
162 fn span(&self) -> Span {
163 let hash_span = match &self.hash_kind {
164 AttributeHashKind::Inner(hash_bang_token) => hash_bang_token.span(),
165 AttributeHashKind::Outer(hash_token) => hash_token.span(),
166 };
167 Span::join(hash_span, &self.attribute.span())
168 }
169}
170
171#[derive(Clone, Debug, Serialize)]
193pub enum AttributeHashKind {
194 Inner(HashBangToken),
197 Outer(HashToken),
200}
201
202impl Spanned for AttributeHashKind {
203 fn span(&self) -> Span {
204 match self {
205 AttributeHashKind::Inner(token) => token.span(),
206 AttributeHashKind::Outer(token) => token.span(),
207 }
208 }
209}
210
211#[derive(Clone, Debug, Serialize)]
212pub struct AttributeArg {
213 pub name: Ident,
214 pub value: Option<Literal>,
215}
216
217impl Spanned for AttributeArg {
218 fn span(&self) -> Span {
219 if let Some(value) = &self.value {
220 Span::join(self.name.span(), &value.span())
221 } else {
222 self.name.span()
223 }
224 }
225}
226
227#[derive(Clone, Debug, Serialize)]
228pub struct Attribute {
229 pub name: Ident,
230 pub args: Option<Parens<Punctuated<AttributeArg, CommaToken>>>,
231}
232
233impl Attribute {
234 pub fn is_doc_comment(&self) -> bool {
235 self.name.as_str() == DOC_COMMENT_ATTRIBUTE_NAME
236 }
237 pub fn is_cfg(&self) -> bool {
238 self.name.as_str() == CFG_ATTRIBUTE_NAME
239 }
240}
241
242impl Spanned for Attribute {
243 fn span(&self) -> Span {
244 self.args
245 .as_ref()
246 .map(|args| Span::join(self.name.span(), &args.span()))
247 .unwrap_or_else(|| self.name.span())
248 }
249}