solidhunter_lib/rules/best_practises/
no_empty_block.rs

1use crate::linter::SolidFile;
2use crate::rules::types::*;
3use crate::types::*;
4use osmium_libs_solidity_ast_extractor::{
5    retriever::{retrieve_block_nodes, retrieve_contract_nodes},
6    Spanned,
7};
8
9// global
10pub const RULE_ID: &str = "no-empty-block";
11
12// specific
13const DEFAULT_SEVERITY: Severity = Severity::WARNING;
14const DEFAULT_MESSAGE: &str = "Code contains empty blocks";
15
16pub struct NoEmptyBlock {
17    data: RuleEntry,
18}
19
20impl RuleType for NoEmptyBlock {
21    fn diagnose(&self, _file: &SolidFile, _files: &[SolidFile]) -> Vec<LintDiag> {
22        let mut res = Vec::new();
23        let _reports = check_empty_block(_file);
24        for report in _reports.iter().flatten() {
25            res.push(LintDiag {
26                id: RULE_ID.to_string(),
27                severity: self.data.severity,
28                range: report.clone(),
29                code: None,
30                source: None,
31                message: DEFAULT_MESSAGE.to_string(),
32                uri: _file.path.clone(),
33            });
34        }
35        res
36    }
37}
38
39fn check_empty_block(file: &SolidFile) -> Vec<Option<Range>> {
40    let mut res: Vec<Option<Range>> = Vec::new();
41
42    let contracts = retrieve_contract_nodes(&file.data);
43    for contract in contracts.iter() {
44        if contract.body.is_empty() {
45            res.push(Some(Range {
46                start: Position {
47                    line: contract.span().start().line,
48                    character: contract.span().start().column + 1,
49                },
50                end: Position {
51                    line: contract.span().end().line,
52                    character: contract.span().end().column,
53                },
54            }));
55        }
56    }
57
58    let blocks = retrieve_block_nodes(&file.data);
59    for block in blocks.iter() {
60        if block.stmts.is_empty() {
61            res.push(Some(Range {
62                start: Position {
63                    line: block.span().start().line,
64                    character: block.span().start().column + 1,
65                },
66                end: Position {
67                    line: block.span().end().line,
68                    character: block.span().end().column,
69                },
70            }));
71        }
72    }
73    res
74}
75
76impl NoEmptyBlock {
77    pub fn create(data: RuleEntry) -> Box<dyn RuleType> {
78        let rule = NoEmptyBlock { data };
79        Box::new(rule)
80    }
81
82    pub fn create_default() -> RuleEntry {
83        RuleEntry {
84            id: RULE_ID.to_string(),
85            severity: DEFAULT_SEVERITY,
86            data: None,
87        }
88    }
89}