solidhunter_lib/rules/best_practises/
custom_errors.rs

1use crate::linter::SolidFile;
2use crate::rules::types::*;
3use crate::types::*;
4use osmium_libs_solidity_ast_extractor::*;
5
6// global
7pub const RULE_ID: &str = "custom-errors";
8
9// specific
10const DEFAULT_SEVERITY: Severity = Severity::WARNING;
11
12pub struct CustomErrors {
13    data: RuleEntry,
14}
15
16impl CustomErrors {
17    fn create_diag(
18        &self,
19        file: &SolidFile,
20        location: (LineColumn, LineColumn),
21        diag_type: String,
22    ) -> LintDiag {
23        LintDiag {
24            id: RULE_ID.to_string(),
25            range: Range {
26                start: Position {
27                    line: location.0.line,
28                    character: location.0.column,
29                },
30                end: Position {
31                    line: location.1.line,
32                    character: location.1.column,
33                },
34            },
35            message: format!("Use Custom Errors instead of {} statements", diag_type),
36            severity: self.data.severity,
37            code: None,
38            source: None,
39            uri: file.path.clone(),
40        }
41    }
42}
43
44impl RuleType for CustomErrors {
45    fn diagnose(&self, file: &SolidFile, _files: &[SolidFile]) -> Vec<LintDiag> {
46        let mut res = Vec::new();
47
48        for contract in retriever::retrieve_contract_nodes(&file.data) {
49            for stmt in retriever::retrieve_stmts_nodes(&contract) {
50                if let Stmt::Revert(revert) = &stmt {
51                    if let Expr::Tuple(_) = &revert.expr {
52                        let location = (revert.span().start(), revert.expr.span().end());
53                        res.push(self.create_diag(file, location, "revert".to_string()));
54                    }
55                }
56                if let Stmt::Expr(expr) = &stmt {
57                    if let Expr::Call(call) = &expr.expr {
58                        if let Expr::Ident(ref ident) = *(call.expr) {
59                            if *ident == "require" || *ident == "assert" {
60                                let location = (call.span().start(), call.span().end());
61                                res.push(self.create_diag(file, location, ident.to_string()));
62                            }
63                        }
64                    }
65                }
66            }
67        }
68        res
69    }
70}
71
72impl CustomErrors {
73    pub(crate) fn create(data: RuleEntry) -> Box<dyn RuleType> {
74        let rule = CustomErrors { data };
75        Box::new(rule)
76    }
77
78    pub(crate) fn create_default() -> RuleEntry {
79        RuleEntry {
80            id: RULE_ID.to_string(),
81            severity: DEFAULT_SEVERITY,
82            data: None,
83        }
84    }
85}