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::ErrorKind,
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(ErrorKind),
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(ErrorKind::NatspecParsingError { span: span_a, .. }),
128 Self::NatspecParsingError(ErrorKind::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(ErrorKind::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(ErrorKind::NatspecParsingError { span, .. }) => {
176 Some(span)
177 }
178 Definition::NatspecParsingError(_) => None,
179 }
180 }
181}
182
183impl Validate for Definition {
184 fn validate(&self, options: &ValidationOptions) -> ItemDiagnostics {
186 match self {
187 Definition::NatspecParsingError(error) => {
189 let (parent, span, message) = match error {
190 ErrorKind::NatspecParsingError {
191 parent,
192 span,
193 message,
194 } => (parent.clone(), span.clone(), message.clone()),
195 _ => (None, TextRange::default(), error.to_string()),
196 };
197 ItemDiagnostics {
198 parent,
199 item_type: ItemType::ParsingError,
200 name: "",
201 span: span.clone(),
202 diags: vec![Diagnostic { span, message }],
203 }
204 }
205 Definition::Contract(def) => def.validate(options),
206 Definition::Interface(def) => def.validate(options),
207 Definition::Library(def) => def.validate(options),
208 Definition::Constructor(def) => def.validate(options),
209 Definition::Enumeration(def) => def.validate(options),
210 Definition::Error(def) => def.validate(options),
211 Definition::Event(def) => def.validate(options),
212 Definition::Function(def) => def.validate(options),
213 Definition::Modifier(def) => def.validate(options),
214 Definition::Struct(def) => def.validate(options),
215 Definition::Variable(def) => def.validate(options),
216 }
217 }
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display, FromStr)]
222#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
223#[serde(rename_all = "snake_case")]
224#[display(rename_all = "kebab-case")] pub enum ContractType {
226 Contract,
227 Interface,
228 Library,
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display, FromStr)]
233#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
234#[serde(rename_all = "snake_case")]
235#[display(rename_all = "snake_case")]
236#[from_str(rename_all = "kebab-case")] pub enum ItemType {
238 Contract,
239 Interface,
240 Library,
241 Constructor,
242 Enum,
243 Error,
244 Event,
245 #[display("function")]
246 PrivateFunction,
247 #[display("function")]
248 InternalFunction,
249 #[display("function")]
250 PublicFunction,
251 #[display("function")]
252 ExternalFunction,
253 Modifier,
254 ParsingError,
255 Struct,
256 #[display("variable")]
257 PrivateVariable,
258 #[display("variable")]
259 InternalVariable,
260 #[display("variable")]
261 PublicVariable,
262}
263
264#[cfg(test)]
265mod tests {
266 use std::str::FromStr;
267
268 use super::*;
269
270 #[test]
271 fn test_contract_type_display() {
272 assert_eq!(ContractType::Contract.to_string(), "contract");
273 assert_eq!(ContractType::Interface.to_string(), "interface");
274 assert_eq!(ContractType::Library.to_string(), "library");
275 }
276
277 #[test]
278 fn test_contract_type_from_str() {
279 assert_eq!(
280 ContractType::from_str("contract").unwrap(),
281 ContractType::Contract
282 );
283 assert_eq!(
284 ContractType::from_str("interface").unwrap(),
285 ContractType::Interface
286 );
287 assert_eq!(
288 ContractType::from_str("library").unwrap(),
289 ContractType::Library
290 );
291 }
292
293 #[test]
294 fn test_contract_type_from_str_case_insensitive() {
295 assert_eq!(
297 ContractType::from_str("Contract").unwrap(),
298 ContractType::Contract
299 );
300 assert_eq!(
301 ContractType::from_str("INTERFACE").unwrap(),
302 ContractType::Interface
303 );
304 assert_eq!(
305 ContractType::from_str("Library").unwrap(),
306 ContractType::Library
307 );
308 }
309
310 #[test]
311 fn test_contract_type_from_str_invalid() {
312 assert!(ContractType::from_str("invalid").is_err());
313 assert!(ContractType::from_str("").is_err());
314 }
315
316 #[test]
317 fn test_item_type_display() {
318 assert_eq!(ItemType::Contract.to_string(), "contract");
319 assert_eq!(ItemType::Interface.to_string(), "interface");
320 assert_eq!(ItemType::Library.to_string(), "library");
321 assert_eq!(ItemType::Constructor.to_string(), "constructor");
322 assert_eq!(ItemType::Enum.to_string(), "enum");
323 assert_eq!(ItemType::Error.to_string(), "error");
324 assert_eq!(ItemType::Event.to_string(), "event");
325 assert_eq!(ItemType::Modifier.to_string(), "modifier");
326 assert_eq!(ItemType::ParsingError.to_string(), "parsing_error");
327 assert_eq!(ItemType::Struct.to_string(), "struct");
328 assert_eq!(ItemType::PrivateFunction.to_string(), "function");
329 assert_eq!(ItemType::InternalFunction.to_string(), "function");
330 assert_eq!(ItemType::PublicFunction.to_string(), "function");
331 assert_eq!(ItemType::ExternalFunction.to_string(), "function");
332 assert_eq!(ItemType::PrivateVariable.to_string(), "variable");
333 assert_eq!(ItemType::InternalVariable.to_string(), "variable");
334 assert_eq!(ItemType::PublicVariable.to_string(), "variable");
335 }
336
337 #[test]
338 fn test_item_type_from_str() {
339 assert_eq!(ItemType::from_str("contract").unwrap(), ItemType::Contract);
340 assert_eq!(
341 ItemType::from_str("interface").unwrap(),
342 ItemType::Interface
343 );
344 assert_eq!(ItemType::from_str("library").unwrap(), ItemType::Library);
345 assert_eq!(
346 ItemType::from_str("constructor").unwrap(),
347 ItemType::Constructor
348 );
349 assert_eq!(ItemType::from_str("enum").unwrap(), ItemType::Enum);
350 assert_eq!(ItemType::from_str("error").unwrap(), ItemType::Error);
351 assert_eq!(ItemType::from_str("event").unwrap(), ItemType::Event);
352 assert_eq!(ItemType::from_str("modifier").unwrap(), ItemType::Modifier);
353 assert_eq!(
354 ItemType::from_str("parsing-error").unwrap(),
355 ItemType::ParsingError
356 );
357 assert_eq!(ItemType::from_str("struct").unwrap(), ItemType::Struct);
358 assert_eq!(
359 ItemType::from_str("private-function").unwrap(),
360 ItemType::PrivateFunction
361 );
362 assert_eq!(
363 ItemType::from_str("internal-function").unwrap(),
364 ItemType::InternalFunction
365 );
366 assert_eq!(
367 ItemType::from_str("public-function").unwrap(),
368 ItemType::PublicFunction
369 );
370 assert_eq!(
371 ItemType::from_str("external-function").unwrap(),
372 ItemType::ExternalFunction
373 );
374 assert_eq!(
375 ItemType::from_str("private-variable").unwrap(),
376 ItemType::PrivateVariable
377 );
378 assert_eq!(
379 ItemType::from_str("internal-variable").unwrap(),
380 ItemType::InternalVariable
381 );
382 assert_eq!(
383 ItemType::from_str("public-variable").unwrap(),
384 ItemType::PublicVariable
385 );
386 }
387
388 #[test]
389 fn test_item_type_from_str_case_sensitive() {
390 assert!(ItemType::from_str("Contract").is_err());
391 assert!(ItemType::from_str("PRIVATE_FUNCTION").is_err());
392 assert!(ItemType::from_str("PrivateFunction").is_err());
393 }
394
395 #[test]
396 fn test_item_type_from_str_invalid() {
397 assert!(ItemType::from_str("invalid").is_err());
398 assert!(ItemType::from_str("function").is_err()); assert!(ItemType::from_str("variable").is_err()); assert!(ItemType::from_str("").is_err());
401 }
402}