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 KNOWN_ATTRIBUTE_NAMES: &[&str] = &[
65 STORAGE_ATTRIBUTE_NAME,
66 DOC_COMMENT_ATTRIBUTE_NAME,
67 TEST_ATTRIBUTE_NAME,
68 INLINE_ATTRIBUTE_NAME,
69 PAYABLE_ATTRIBUTE_NAME,
70 ALLOW_ATTRIBUTE_NAME,
71 CFG_ATTRIBUTE_NAME,
72 DEPRECATED_ATTRIBUTE_NAME,
73 FALLBACK_ATTRIBUTE_NAME,
74 ABI_NAME_ATTRIBUTE_NAME,
75];
76
77#[derive(Clone, Debug, Serialize)]
99pub struct AttributeDecl {
100 pub hash_kind: AttributeHashKind,
101 pub attribute: SquareBrackets<Punctuated<Attribute, CommaToken>>,
102}
103
104impl AttributeDecl {
105 pub fn new_outer_doc_comment(span: Span, content_span: Span) -> Self {
112 Self::new_doc_comment(
113 span.clone(),
114 content_span,
115 AttributeHashKind::Outer(HashToken::new(span)),
116 )
117 }
118
119 pub fn new_inner_doc_comment(span: Span, content_span: Span) -> Self {
126 Self::new_doc_comment(
127 span.clone(),
128 content_span,
129 AttributeHashKind::Inner(HashBangToken::new(span)),
130 )
131 }
132
133 fn new_doc_comment(span: Span, content_span: Span, hash_kind: AttributeHashKind) -> Self {
134 let name = Ident::new_no_trim(content_span.clone());
137 AttributeDecl {
138 hash_kind,
139 attribute: SquareBrackets::new(
140 Punctuated::single(Attribute {
141 name: Ident::new_with_override(
142 DOC_COMMENT_ATTRIBUTE_NAME.to_string(),
143 span.clone(),
144 ),
145 args: Some(Parens::new(
146 Punctuated::single(AttributeArg { name, value: None }),
147 content_span,
148 )),
149 }),
150 span,
151 ),
152 }
153 }
154
155 pub fn is_doc_comment(&self) -> bool {
157 self.attribute.inner.value_separator_pairs.is_empty()
158 && self
159 .attribute
160 .inner
161 .final_value_opt
162 .as_ref()
163 .is_some_and(|attr| attr.is_doc_comment())
164 }
165
166 pub fn is_inner(&self) -> bool {
167 matches!(self.hash_kind, AttributeHashKind::Inner(_))
168 }
169}
170
171impl Spanned for AttributeDecl {
172 fn span(&self) -> Span {
173 let hash_span = match &self.hash_kind {
174 AttributeHashKind::Inner(hash_bang_token) => hash_bang_token.span(),
175 AttributeHashKind::Outer(hash_token) => hash_token.span(),
176 };
177 Span::join(hash_span, &self.attribute.span())
178 }
179}
180
181#[derive(Clone, Debug, Serialize)]
203pub enum AttributeHashKind {
204 Inner(HashBangToken),
207 Outer(HashToken),
210}
211
212impl Spanned for AttributeHashKind {
213 fn span(&self) -> Span {
214 match self {
215 AttributeHashKind::Inner(token) => token.span(),
216 AttributeHashKind::Outer(token) => token.span(),
217 }
218 }
219}
220
221#[derive(Clone, Debug, Serialize)]
222pub struct AttributeArg {
223 pub name: Ident,
224 pub value: Option<Literal>,
225}
226
227impl Spanned for AttributeArg {
228 fn span(&self) -> Span {
229 if let Some(value) = &self.value {
230 Span::join(self.name.span(), &value.span())
231 } else {
232 self.name.span()
233 }
234 }
235}
236
237#[derive(Clone, Debug, Serialize)]
238pub struct Attribute {
239 pub name: Ident,
240 pub args: Option<Parens<Punctuated<AttributeArg, CommaToken>>>,
241}
242
243impl Attribute {
244 pub fn is_doc_comment(&self) -> bool {
245 self.name.as_str() == DOC_COMMENT_ATTRIBUTE_NAME
246 }
247 pub fn is_cfg(&self) -> bool {
248 self.name.as_str() == CFG_ATTRIBUTE_NAME
249 }
250}
251
252impl Spanned for Attribute {
253 fn span(&self) -> Span {
254 self.args
255 .as_ref()
256 .map(|args| Span::join(self.name.span(), &args.span()))
257 .unwrap_or_else(|| self.name.span())
258 }
259}