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 TRACE_ATTRIBUTE_NAME: &str = "trace";
57pub const TRACE_NEVER_ARG_NAME: &str = "never";
58pub const TRACE_ALWAYS_ARG_NAME: &str = "always";
59
60pub const ABI_NAME_ATTRIBUTE_NAME: &str = "abi_name";
62pub const ABI_NAME_NAME_ARG_NAME: &str = "name";
63
64pub const EVENT_ATTRIBUTE_NAME: &str = "event";
66pub const INDEXED_ATTRIBUTE_NAME: &str = "indexed";
67
68pub const KNOWN_ATTRIBUTE_NAMES: &[&str] = &[
69 STORAGE_ATTRIBUTE_NAME,
70 DOC_COMMENT_ATTRIBUTE_NAME,
71 TEST_ATTRIBUTE_NAME,
72 INLINE_ATTRIBUTE_NAME,
73 PAYABLE_ATTRIBUTE_NAME,
74 ALLOW_ATTRIBUTE_NAME,
75 CFG_ATTRIBUTE_NAME,
76 DEPRECATED_ATTRIBUTE_NAME,
77 FALLBACK_ATTRIBUTE_NAME,
78 ABI_NAME_ATTRIBUTE_NAME,
79 EVENT_ATTRIBUTE_NAME,
80 INDEXED_ATTRIBUTE_NAME,
81];
82
83#[derive(Clone, Debug, Serialize)]
105pub struct AttributeDecl {
106 pub hash_kind: AttributeHashKind,
107 pub attribute: SquareBrackets<Punctuated<Attribute, CommaToken>>,
108}
109
110impl AttributeDecl {
111 pub fn new_outer_doc_comment(span: Span, content_span: Span) -> Self {
118 Self::new_doc_comment(
119 span.clone(),
120 content_span,
121 AttributeHashKind::Outer(HashToken::new(span)),
122 )
123 }
124
125 pub fn new_inner_doc_comment(span: Span, content_span: Span) -> Self {
132 Self::new_doc_comment(
133 span.clone(),
134 content_span,
135 AttributeHashKind::Inner(HashBangToken::new(span)),
136 )
137 }
138
139 fn new_doc_comment(span: Span, content_span: Span, hash_kind: AttributeHashKind) -> Self {
140 let name = Ident::new_no_trim(content_span.clone());
143 AttributeDecl {
144 hash_kind,
145 attribute: SquareBrackets::new(
146 Punctuated::single(Attribute {
147 name: Ident::new_with_override(
148 DOC_COMMENT_ATTRIBUTE_NAME.to_string(),
149 span.clone(),
150 ),
151 args: Some(Parens::new(
152 Punctuated::single(AttributeArg { name, value: None }),
153 content_span,
154 )),
155 }),
156 span,
157 ),
158 }
159 }
160
161 pub fn is_doc_comment(&self) -> bool {
163 self.attribute.inner.value_separator_pairs.is_empty()
164 && self
165 .attribute
166 .inner
167 .final_value_opt
168 .as_ref()
169 .is_some_and(|attr| attr.is_doc_comment())
170 }
171
172 pub fn is_inner(&self) -> bool {
173 matches!(self.hash_kind, AttributeHashKind::Inner(_))
174 }
175}
176
177impl Spanned for AttributeDecl {
178 fn span(&self) -> Span {
179 let hash_span = match &self.hash_kind {
180 AttributeHashKind::Inner(hash_bang_token) => hash_bang_token.span(),
181 AttributeHashKind::Outer(hash_token) => hash_token.span(),
182 };
183 Span::join(hash_span, &self.attribute.span())
184 }
185}
186
187#[derive(Clone, Debug, Serialize)]
209pub enum AttributeHashKind {
210 Inner(HashBangToken),
213 Outer(HashToken),
216}
217
218impl Spanned for AttributeHashKind {
219 fn span(&self) -> Span {
220 match self {
221 AttributeHashKind::Inner(token) => token.span(),
222 AttributeHashKind::Outer(token) => token.span(),
223 }
224 }
225}
226
227#[derive(Clone, Debug, Serialize)]
228pub struct AttributeArg {
229 pub name: Ident,
230 pub value: Option<Literal>,
231}
232
233impl Spanned for AttributeArg {
234 fn span(&self) -> Span {
235 if let Some(value) = &self.value {
236 Span::join(self.name.span(), &value.span())
237 } else {
238 self.name.span()
239 }
240 }
241}
242
243#[derive(Clone, Debug, Serialize)]
244pub struct Attribute {
245 pub name: Ident,
246 pub args: Option<Parens<Punctuated<AttributeArg, CommaToken>>>,
247}
248
249impl Attribute {
250 pub fn is_doc_comment(&self) -> bool {
251 self.name.as_str() == DOC_COMMENT_ATTRIBUTE_NAME
252 }
253 pub fn is_cfg(&self) -> bool {
254 self.name.as_str() == CFG_ATTRIBUTE_NAME
255 }
256}
257
258impl Spanned for Attribute {
259 fn span(&self) -> Span {
260 self.args
261 .as_ref()
262 .map(|args| Span::join(self.name.span(), &args.span()))
263 .unwrap_or_else(|| self.name.span())
264 }
265}