1use constructor::ConstructorDefinition;
6use contract::ContractDefinition;
7use derive_more::{Display, From, FromStr, IsVariant, TryInto};
8use enumeration::EnumDefinition;
9use error::ErrorDefinition;
10use event::EventDefinition;
11use function::FunctionDefinition;
12use lintspec_macros::AsToVariant;
13use modifier::ModifierDefinition;
14use serde::{Deserialize, Serialize};
15use structure::StructDefinition;
16use variable::VariableDeclaration;
17
18use crate::{
19 definitions::{interface::InterfaceDefinition, library::LibraryDefinition},
20 error::Error,
21 interner::Symbol,
22 lint::{Diagnostic, ItemDiagnostics, Validate, ValidationOptions},
23 textindex::TextRange,
24};
25
26pub mod constructor;
27pub mod contract;
28pub mod enumeration;
29pub mod error;
30pub mod event;
31pub mod function;
32pub mod interface;
33pub mod library;
34pub mod modifier;
35pub mod structure;
36pub mod variable;
37
38pub trait SourceItem {
40 fn item_type(&self) -> ItemType;
41
42 fn parent(&self) -> Option<Parent>;
44
45 fn name(&self) -> Symbol;
47
48 fn span(&self) -> TextRange;
50}
51
52#[derive(Debug, Clone, bon::Builder)]
56#[builder(on(String, into))]
57pub struct Identifier {
58 pub name: Option<Symbol>,
59 pub span: TextRange,
60}
61
62#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
66pub enum Visibility {
67 External,
68 #[default]
69 Internal,
70 Private,
71 Public,
72}
73
74#[derive(Debug, Clone, Copy, Default, bon::Builder)]
76#[non_exhaustive]
77pub struct Attributes {
78 pub visibility: Visibility,
79 pub r#override: bool,
80}
81
82#[derive(Debug, Clone, Display, Serialize, PartialEq, Eq, IsVariant)]
84#[serde(untagged)]
85pub enum Parent {
86 Contract(&'static str),
87 Interface(&'static str),
88 Library(&'static str),
89}
90
91#[derive(Debug, From, TryInto, IsVariant, AsToVariant)]
93pub enum Definition {
94 Contract(ContractDefinition),
95 Interface(InterfaceDefinition),
96 Library(LibraryDefinition),
97 Constructor(ConstructorDefinition),
98 Enumeration(EnumDefinition),
99 Error(ErrorDefinition),
100 Event(EventDefinition),
101 Function(FunctionDefinition),
102 Modifier(ModifierDefinition),
103 Struct(StructDefinition),
104 Variable(VariableDeclaration),
105 NatspecParsingError(Error),
106}
107
108impl PartialEq for Definition {
109 fn eq(&self, other: &Self) -> bool {
114 match (self, other) {
115 (Self::Contract(a), Self::Contract(b)) => a.span.start == b.span.start,
116 (Self::Interface(a), Self::Interface(b)) => a.span.start == b.span.start,
117 (Self::Library(a), Self::Library(b)) => a.span.start == b.span.start,
118 (Self::Constructor(a), Self::Constructor(b)) => a.span.start == b.span.start,
119 (Self::Enumeration(a), Self::Enumeration(b)) => a.span.start == b.span.start,
120 (Self::Error(a), Self::Error(b)) => a.span.start == b.span.start,
121 (Self::Event(a), Self::Event(b)) => a.span.start == b.span.start,
122 (Self::Function(a), Self::Function(b)) => a.span.start == b.span.start,
123 (Self::Modifier(a), Self::Modifier(b)) => a.span.start == b.span.start,
124 (Self::Struct(a), Self::Struct(b)) => a.span.start == b.span.start,
125 (Self::Variable(a), Self::Variable(b)) => a.span.start == b.span.start,
126 (
127 Self::NatspecParsingError(Error::NatspecParsingError { span: span_a, .. }),
128 Self::NatspecParsingError(Error::NatspecParsingError { span: span_b, .. }),
129 ) => span_a.start == span_b.start,
130 (Self::NatspecParsingError(a), Self::NatspecParsingError(b)) => {
131 a.to_string() == b.to_string() }
133 _ => false,
134 }
135 }
136}
137
138impl Definition {
139 #[must_use]
141 pub fn span(&self) -> Option<TextRange> {
142 match self {
143 Definition::Contract(d) => Some(d.span()),
144 Definition::Interface(d) => Some(d.span()),
145 Definition::Library(d) => Some(d.span()),
146 Definition::Constructor(d) => Some(d.span()),
147 Definition::Enumeration(d) => Some(d.span()),
148 Definition::Error(d) => Some(d.span()),
149 Definition::Event(d) => Some(d.span()),
150 Definition::Function(d) => Some(d.span()),
151 Definition::Modifier(d) => Some(d.span()),
152 Definition::Struct(d) => Some(d.span()),
153 Definition::Variable(d) => Some(d.span()),
154 Definition::NatspecParsingError(Error::NatspecParsingError { span, .. }) => {
155 Some(span.clone())
156 }
157 Definition::NatspecParsingError(_) => None,
158 }
159 }
160
161 pub fn span_mut(&mut self) -> Option<&mut TextRange> {
163 match self {
164 Definition::Contract(d) => Some(&mut d.span),
165 Definition::Interface(d) => Some(&mut d.span),
166 Definition::Library(d) => Some(&mut d.span),
167 Definition::Constructor(d) => Some(&mut d.span),
168 Definition::Enumeration(d) => Some(&mut d.span),
169 Definition::Error(d) => Some(&mut d.span),
170 Definition::Event(d) => Some(&mut d.span),
171 Definition::Function(d) => Some(&mut d.span),
172 Definition::Modifier(d) => Some(&mut d.span),
173 Definition::Struct(d) => Some(&mut d.span),
174 Definition::Variable(d) => Some(&mut d.span),
175 Definition::NatspecParsingError(Error::NatspecParsingError { span, .. }) => Some(span),
176 Definition::NatspecParsingError(_) => None,
177 }
178 }
179}
180
181impl Validate for Definition {
182 fn validate(&self, options: &ValidationOptions) -> ItemDiagnostics {
184 match self {
185 Definition::NatspecParsingError(error) => {
187 let (parent, span, message) = match error {
188 Error::NatspecParsingError {
189 parent,
190 span,
191 message,
192 } => (parent.clone(), span.clone(), message.clone()),
193 _ => (None, TextRange::default(), error.to_string()),
194 };
195 ItemDiagnostics {
196 parent,
197 item_type: ItemType::ParsingError,
198 name: "",
199 span: span.clone(),
200 diags: vec![Diagnostic { span, message }],
201 }
202 }
203 Definition::Contract(def) => def.validate(options),
204 Definition::Interface(def) => def.validate(options),
205 Definition::Library(def) => def.validate(options),
206 Definition::Constructor(def) => def.validate(options),
207 Definition::Enumeration(def) => def.validate(options),
208 Definition::Error(def) => def.validate(options),
209 Definition::Event(def) => def.validate(options),
210 Definition::Function(def) => def.validate(options),
211 Definition::Modifier(def) => def.validate(options),
212 Definition::Struct(def) => def.validate(options),
213 Definition::Variable(def) => def.validate(options),
214 }
215 }
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display, FromStr)]
220#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
221#[serde(rename_all = "snake_case")]
222#[display(rename_all = "kebab-case")] pub enum ContractType {
224 Contract,
225 Interface,
226 Library,
227}
228
229#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display, FromStr)]
231#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
232#[serde(rename_all = "snake_case")]
233#[display(rename_all = "snake_case")]
234#[from_str(rename_all = "kebab-case")] pub enum ItemType {
236 Contract,
237 Interface,
238 Library,
239 Constructor,
240 Enum,
241 Error,
242 Event,
243 #[display("function")]
244 PrivateFunction,
245 #[display("function")]
246 InternalFunction,
247 #[display("function")]
248 PublicFunction,
249 #[display("function")]
250 ExternalFunction,
251 Modifier,
252 ParsingError,
253 Struct,
254 #[display("variable")]
255 PrivateVariable,
256 #[display("variable")]
257 InternalVariable,
258 #[display("variable")]
259 PublicVariable,
260}
261
262#[cfg(test)]
263mod tests {
264 use std::str::FromStr;
265
266 use super::*;
267
268 #[test]
269 fn test_contract_type_display() {
270 assert_eq!(ContractType::Contract.to_string(), "contract");
271 assert_eq!(ContractType::Interface.to_string(), "interface");
272 assert_eq!(ContractType::Library.to_string(), "library");
273 }
274
275 #[test]
276 fn test_contract_type_from_str() {
277 assert_eq!(
278 ContractType::from_str("contract").unwrap(),
279 ContractType::Contract
280 );
281 assert_eq!(
282 ContractType::from_str("interface").unwrap(),
283 ContractType::Interface
284 );
285 assert_eq!(
286 ContractType::from_str("library").unwrap(),
287 ContractType::Library
288 );
289 }
290
291 #[test]
292 fn test_contract_type_from_str_case_insensitive() {
293 assert_eq!(
295 ContractType::from_str("Contract").unwrap(),
296 ContractType::Contract
297 );
298 assert_eq!(
299 ContractType::from_str("INTERFACE").unwrap(),
300 ContractType::Interface
301 );
302 assert_eq!(
303 ContractType::from_str("Library").unwrap(),
304 ContractType::Library
305 );
306 }
307
308 #[test]
309 fn test_contract_type_from_str_invalid() {
310 assert!(ContractType::from_str("invalid").is_err());
311 assert!(ContractType::from_str("").is_err());
312 }
313
314 #[test]
315 fn test_item_type_display() {
316 assert_eq!(ItemType::Contract.to_string(), "contract");
317 assert_eq!(ItemType::Interface.to_string(), "interface");
318 assert_eq!(ItemType::Library.to_string(), "library");
319 assert_eq!(ItemType::Constructor.to_string(), "constructor");
320 assert_eq!(ItemType::Enum.to_string(), "enum");
321 assert_eq!(ItemType::Error.to_string(), "error");
322 assert_eq!(ItemType::Event.to_string(), "event");
323 assert_eq!(ItemType::Modifier.to_string(), "modifier");
324 assert_eq!(ItemType::ParsingError.to_string(), "parsing_error");
325 assert_eq!(ItemType::Struct.to_string(), "struct");
326 assert_eq!(ItemType::PrivateFunction.to_string(), "function");
327 assert_eq!(ItemType::InternalFunction.to_string(), "function");
328 assert_eq!(ItemType::PublicFunction.to_string(), "function");
329 assert_eq!(ItemType::ExternalFunction.to_string(), "function");
330 assert_eq!(ItemType::PrivateVariable.to_string(), "variable");
331 assert_eq!(ItemType::InternalVariable.to_string(), "variable");
332 assert_eq!(ItemType::PublicVariable.to_string(), "variable");
333 }
334
335 #[test]
336 fn test_item_type_from_str() {
337 assert_eq!(ItemType::from_str("contract").unwrap(), ItemType::Contract);
338 assert_eq!(
339 ItemType::from_str("interface").unwrap(),
340 ItemType::Interface
341 );
342 assert_eq!(ItemType::from_str("library").unwrap(), ItemType::Library);
343 assert_eq!(
344 ItemType::from_str("constructor").unwrap(),
345 ItemType::Constructor
346 );
347 assert_eq!(ItemType::from_str("enum").unwrap(), ItemType::Enum);
348 assert_eq!(ItemType::from_str("error").unwrap(), ItemType::Error);
349 assert_eq!(ItemType::from_str("event").unwrap(), ItemType::Event);
350 assert_eq!(ItemType::from_str("modifier").unwrap(), ItemType::Modifier);
351 assert_eq!(
352 ItemType::from_str("parsing-error").unwrap(),
353 ItemType::ParsingError
354 );
355 assert_eq!(ItemType::from_str("struct").unwrap(), ItemType::Struct);
356 assert_eq!(
357 ItemType::from_str("private-function").unwrap(),
358 ItemType::PrivateFunction
359 );
360 assert_eq!(
361 ItemType::from_str("internal-function").unwrap(),
362 ItemType::InternalFunction
363 );
364 assert_eq!(
365 ItemType::from_str("public-function").unwrap(),
366 ItemType::PublicFunction
367 );
368 assert_eq!(
369 ItemType::from_str("external-function").unwrap(),
370 ItemType::ExternalFunction
371 );
372 assert_eq!(
373 ItemType::from_str("private-variable").unwrap(),
374 ItemType::PrivateVariable
375 );
376 assert_eq!(
377 ItemType::from_str("internal-variable").unwrap(),
378 ItemType::InternalVariable
379 );
380 assert_eq!(
381 ItemType::from_str("public-variable").unwrap(),
382 ItemType::PublicVariable
383 );
384 }
385
386 #[test]
387 fn test_item_type_from_str_case_sensitive() {
388 assert!(ItemType::from_str("Contract").is_err());
389 assert!(ItemType::from_str("PRIVATE_FUNCTION").is_err());
390 assert!(ItemType::from_str("PrivateFunction").is_err());
391 }
392
393 #[test]
394 fn test_item_type_from_str_invalid() {
395 assert!(ItemType::from_str("invalid").is_err());
396 assert!(ItemType::from_str("function").is_err()); assert!(ItemType::from_str("variable").is_err()); assert!(ItemType::from_str("").is_err());
399 }
400}