syn_solidity/attribute/
variable.rs

1use crate::{kw, Override, SolPath, Spanned, Visibility};
2use proc_macro2::Span;
3use std::{
4    fmt,
5    hash::{Hash, Hasher},
6    mem,
7};
8use syn::{
9    parse::{Parse, ParseStream},
10    Error, Result, Token,
11};
12
13/// A list of unique variable attributes.
14#[derive(Clone, Debug)]
15pub struct VariableAttributes(pub Vec<VariableAttribute>);
16
17impl fmt::Display for VariableAttributes {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        for (i, attr) in self.0.iter().enumerate() {
20            if i > 0 {
21                f.write_str(" ")?;
22            }
23            write!(f, "{attr}")?;
24        }
25        Ok(())
26    }
27}
28
29impl Parse for VariableAttributes {
30    fn parse(input: ParseStream<'_>) -> Result<Self> {
31        let mut attributes = Vec::new();
32        while let Ok(attribute) = input.parse::<VariableAttribute>() {
33            let error = |prev: &VariableAttribute| {
34                let mut e = Error::new(attribute.span(), "duplicate attribute");
35                e.combine(Error::new(prev.span(), "previous declaration is here"));
36                e
37            };
38
39            // Only one of: `constant`, `immutable`
40            match attribute {
41                VariableAttribute::Constant(_) => {
42                    if let Some(prev) =
43                        attributes.iter().find(|a| matches!(a, VariableAttribute::Immutable(_)))
44                    {
45                        return Err(error(prev));
46                    }
47                }
48                VariableAttribute::Immutable(_) => {
49                    if let Some(prev) =
50                        attributes.iter().find(|a| matches!(a, VariableAttribute::Constant(_)))
51                    {
52                        return Err(error(prev));
53                    }
54                }
55                _ => {}
56            }
57
58            if let Some(prev) = attributes.iter().find(|a| **a == attribute) {
59                return Err(error(prev));
60            }
61            attributes.push(attribute);
62        }
63        Ok(Self(attributes))
64    }
65}
66
67impl Spanned for VariableAttributes {
68    fn span(&self) -> Span {
69        self.0.span()
70    }
71
72    fn set_span(&mut self, span: Span) {
73        self.0.set_span(span);
74    }
75}
76
77impl VariableAttributes {
78    pub fn visibility(&self) -> Option<Visibility> {
79        self.0.iter().find_map(VariableAttribute::visibility)
80    }
81
82    pub fn has_external(&self) -> bool {
83        self.0.iter().any(VariableAttribute::is_external)
84    }
85
86    pub fn has_internal(&self) -> bool {
87        self.0.iter().any(VariableAttribute::is_internal)
88    }
89
90    pub fn has_private(&self) -> bool {
91        self.0.iter().any(VariableAttribute::is_private)
92    }
93
94    pub fn has_public(&self) -> bool {
95        self.0.iter().any(VariableAttribute::is_public)
96    }
97
98    pub fn has_constant(&self) -> bool {
99        self.0.iter().any(VariableAttribute::is_constant)
100    }
101
102    pub fn has_immutable(&self) -> bool {
103        self.0.iter().any(VariableAttribute::is_immutable)
104    }
105
106    pub fn has_override(&self, path: Option<&SolPath>) -> bool {
107        self.0.iter().any(|attr| attr.is_override(path))
108    }
109}
110
111/// A variable attribute.
112#[derive(Clone)]
113pub enum VariableAttribute {
114    /// A [Visibility] attribute.
115    Visibility(Visibility),
116    /// `constant`.
117    Constant(kw::constant),
118    /// `immutable`.
119    Immutable(kw::immutable),
120    /// An [Override] attribute.
121    Override(Override),
122}
123
124impl fmt::Display for VariableAttribute {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        match self {
127            Self::Visibility(v) => v.fmt(f),
128            Self::Constant(_) => f.write_str("constant"),
129            Self::Immutable(_) => f.write_str("immutable"),
130            Self::Override(o) => o.fmt(f),
131        }
132    }
133}
134
135impl fmt::Debug for VariableAttribute {
136    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137        match self {
138            Self::Visibility(v) => v.fmt(f),
139            Self::Constant(_) => f.write_str("Constant"),
140            Self::Immutable(_) => f.write_str("Immutable"),
141            Self::Override(o) => o.fmt(f),
142        }
143    }
144}
145
146impl PartialEq for VariableAttribute {
147    fn eq(&self, other: &Self) -> bool {
148        mem::discriminant(self) == mem::discriminant(other)
149    }
150}
151
152impl Eq for VariableAttribute {}
153
154impl Hash for VariableAttribute {
155    fn hash<H: Hasher>(&self, state: &mut H) {
156        mem::discriminant(self).hash(state);
157    }
158}
159
160impl Parse for VariableAttribute {
161    fn parse(input: ParseStream<'_>) -> Result<Self> {
162        let lookahead = input.lookahead1();
163        if Visibility::peek(&lookahead) {
164            input.parse().map(Self::Visibility)
165        } else if lookahead.peek(kw::constant) {
166            input.parse().map(Self::Constant)
167        } else if lookahead.peek(Token![override]) {
168            input.parse().map(Self::Override)
169        } else if lookahead.peek(kw::immutable) {
170            input.parse().map(Self::Immutable)
171        } else {
172            Err(lookahead.error())
173        }
174    }
175}
176
177impl Spanned for VariableAttribute {
178    fn span(&self) -> Span {
179        match self {
180            Self::Visibility(v) => v.span(),
181            Self::Constant(c) => c.span,
182            Self::Override(o) => o.span(),
183            Self::Immutable(i) => i.span,
184        }
185    }
186
187    fn set_span(&mut self, span: Span) {
188        match self {
189            Self::Visibility(v) => v.set_span(span),
190            Self::Constant(c) => c.span = span,
191            Self::Override(o) => o.set_span(span),
192            Self::Immutable(i) => i.span = span,
193        }
194    }
195}
196
197impl VariableAttribute {
198    #[inline]
199    pub const fn visibility(&self) -> Option<Visibility> {
200        match self {
201            Self::Visibility(v) => Some(*v),
202            _ => None,
203        }
204    }
205
206    #[inline]
207    pub const fn r#override(&self) -> Option<&Override> {
208        match self {
209            Self::Override(o) => Some(o),
210            _ => None,
211        }
212    }
213
214    #[inline]
215    pub const fn is_external(&self) -> bool {
216        matches!(self, Self::Visibility(Visibility::External(_)))
217    }
218
219    #[inline]
220    pub const fn is_public(&self) -> bool {
221        matches!(self, Self::Visibility(Visibility::Public(_)))
222    }
223
224    #[inline]
225    pub const fn is_internal(&self) -> bool {
226        matches!(self, Self::Visibility(Visibility::Internal(_)))
227    }
228
229    #[inline]
230    pub const fn is_private(&self) -> bool {
231        matches!(self, Self::Visibility(Visibility::Private(_)))
232    }
233
234    #[inline]
235    pub const fn is_constant(&self) -> bool {
236        matches!(self, Self::Constant(_))
237    }
238
239    #[inline]
240    pub const fn is_immutable(&self) -> bool {
241        matches!(self, Self::Immutable(_))
242    }
243
244    #[inline]
245    pub fn is_override(&self, path: Option<&SolPath>) -> bool {
246        self.r#override().is_some_and(|o| match path {
247            Some(path) => o.paths.iter().any(|p| p == path),
248            None => true,
249        })
250    }
251}