sway_core/transform/
attribute.rs

1//! Each item may have a list of attributes, each with a name (the key to the hashmap) and a list of
2//! zero or more args.  Attributes may be specified more than once in which case we use the union of
3//! their args.
4//!
5//! E.g.,
6//!
7//!   #[foo(bar)]
8//!   #[foo(baz, xyzzy)]
9//!
10//! is essentially equivalent to
11//!
12//!   #[foo(bar, baz, xyzzy)]
13//!
14//! and duplicates like
15//!
16//!   #[foo(bar)]
17//!   #[foo(bar)]
18//!
19//! are equivalent to
20//!
21//!   #[foo(bar, bar)]
22
23use indexmap::IndexMap;
24use serde::{Deserialize, Serialize};
25use std::{hash::Hash, sync::Arc};
26use sway_ast::Literal;
27use sway_types::{
28    constants::{
29        ALLOW_DEAD_CODE_NAME, ALLOW_DEPRECATED_NAME, CFG_PROGRAM_TYPE_ARG_NAME, CFG_TARGET_ARG_NAME,
30    },
31    Ident, Span, Spanned,
32};
33
34#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
35pub struct AttributeArg {
36    pub name: Ident,
37    pub value: Option<Literal>,
38    pub span: Span,
39}
40
41impl Spanned for AttributeArg {
42    fn span(&self) -> Span {
43        self.span.clone()
44    }
45}
46
47/// An attribute has a name (i.e "doc", "storage"),
48/// a vector of possible arguments and
49/// a span from its declaration.
50#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
51pub struct Attribute {
52    pub name: Ident,
53    pub args: Vec<AttributeArg>,
54    pub span: Span,
55}
56
57/// Valid kinds of attributes supported by the compiler
58#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
59pub enum AttributeKind {
60    Doc,
61    DocComment,
62    Storage,
63    Inline,
64    Test,
65    Payable,
66    Allow,
67    Cfg,
68    Deprecated,
69    Fallback,
70}
71
72impl AttributeKind {
73    // Returns tuple with the minimum and maximum number of expected args
74    // None can be returned in the second position of the tuple if there is no maximum
75    pub fn expected_args_len_min_max(self) -> (usize, Option<usize>) {
76        use AttributeKind::*;
77        match self {
78            Doc | DocComment | Storage | Inline | Test | Payable | Deprecated | Fallback => {
79                (0, None)
80            }
81            Allow | Cfg => (1, Some(1)),
82        }
83    }
84
85    // Returns the expected values for an attribute argument
86    pub fn expected_args_values(self, _arg_index: usize) -> Option<Vec<String>> {
87        use AttributeKind::*;
88        match self {
89            Deprecated | Doc | DocComment | Storage | Inline | Test | Payable | Fallback => None,
90            Allow => Some(vec![
91                ALLOW_DEAD_CODE_NAME.to_string(),
92                ALLOW_DEPRECATED_NAME.to_string(),
93            ]),
94            Cfg => {
95                let mut cfgs = vec![
96                    CFG_TARGET_ARG_NAME.to_string(),
97                    CFG_PROGRAM_TYPE_ARG_NAME.to_string(),
98                ];
99                cfgs.extend(sway_features::CFG.iter().map(|x| x.to_string()));
100                Some(cfgs)
101            }
102        }
103    }
104}
105
106/// Stores the attributes associated with the type.
107#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
108pub struct AttributesMap(Arc<IndexMap<AttributeKind, Vec<Attribute>>>);
109
110impl AttributesMap {
111    /// Create a new attributes map.
112    pub fn new(attrs_map: Arc<IndexMap<AttributeKind, Vec<Attribute>>>) -> AttributesMap {
113        AttributesMap(attrs_map)
114    }
115
116    /// Returns the first attribute by span, or None if there are no attributes.
117    pub fn first(&self) -> Option<(&AttributeKind, &Attribute)> {
118        let mut first: Option<(&AttributeKind, &Attribute)> = None;
119        for (kind, attrs) in self.iter() {
120            for attr in attrs {
121                if let Some((_, first_attr)) = first {
122                    if attr.span.start() < first_attr.span.start() {
123                        first = Some((kind, attr));
124                    }
125                } else {
126                    first = Some((kind, attr));
127                }
128            }
129        }
130        first
131    }
132
133    pub fn inner(&self) -> &IndexMap<AttributeKind, Vec<Attribute>> {
134        &self.0
135    }
136}
137
138impl std::ops::Deref for AttributesMap {
139    type Target = Arc<IndexMap<AttributeKind, Vec<Attribute>>>;
140    fn deref(&self) -> &Self::Target {
141        &self.0
142    }
143}
144
145pub struct AllowDeprecatedEnterToken {
146    diff: i32,
147}
148
149#[derive(Default)]
150pub struct AllowDeprecatedState {
151    allowed: u32,
152}
153impl AllowDeprecatedState {
154    pub(crate) fn enter(&mut self, attributes: AttributesMap) -> AllowDeprecatedEnterToken {
155        if let Some(all_allows) = attributes.get(&AttributeKind::Allow) {
156            for allow in all_allows {
157                for arg in allow.args.iter() {
158                    if arg.name.as_str() == ALLOW_DEPRECATED_NAME {
159                        self.allowed += 1;
160                        return AllowDeprecatedEnterToken { diff: -1 };
161                    }
162                }
163            }
164        }
165
166        AllowDeprecatedEnterToken { diff: 0 }
167    }
168
169    pub(crate) fn exit(&mut self, token: AllowDeprecatedEnterToken) {
170        self.allowed = self.allowed.saturating_add_signed(token.diff);
171    }
172
173    pub(crate) fn is_allowed(&self) -> bool {
174        self.allowed > 0
175    }
176}