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