Skip to content
This repository was archived by the owner on Nov 9, 2023. It is now read-only.

Commit 2ff6a57

Browse files
author
Alexandre jublot
committed
feat(rules): added ordering rules
1 parent a33d4ca commit 2ff6a57

File tree

3 files changed

+164
-3
lines changed

3 files changed

+164
-3
lines changed

solidhunter-lib/src/rules/naming/func_param_name_camelcase.rs

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ impl RuleType for FuncParamNameCamelcase {
2121
match node {
2222
ContractDefinitionChildNodes::FunctionDefinition(function) => {
2323
for parameter in &function.parameters.parameters {
24+
if parameter.name.is_empty() {
25+
continue;
26+
}
2427
if !(parameter.name.chars().nth(0).unwrap() >= 'a' && parameter.name.chars().nth(0).unwrap() <= 'z') ||
2528
parameter.name.contains("_") ||
2629
parameter.name.contains("-") {
+8-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
use std::collections::HashMap;
22
use crate::rules::types::{RuleEntry, RuleType};
33

4+
use crate::rules::order::import_on_top::ImportOnTop;
5+
use crate::rules::order::ordering::Ordering;
6+
47
#[macro_use]
5-
pub(crate) mod import_on_top;
8+
pub(crate) mod ordering;
69

7-
// List all rules
10+
#[macro_use]
11+
pub(crate) mod import_on_top;
812

9-
use crate::rules::order::import_on_top::ImportOnTop;
1013
use crate::rules::RuleBuilder;
1114

1215
pub fn create_default_rules() -> Vec<RuleEntry> {
1316
let mut rules = Vec::new();
1417

1518
rules.push(ImportOnTop::create_default());
19+
rules.push(Ordering::create_default());
1620

1721
rules
1822
}
@@ -21,6 +25,7 @@ pub fn create_rules() -> HashMap<String, fn(RuleEntry) -> Box<dyn RuleType>> {
2125
let mut rules : HashMap<String, RuleBuilder> = HashMap::new();
2226

2327
rules.insert( "import-on-top".to_string(), ImportOnTop::create);
28+
rules.insert( "ordering".to_string(), Ordering::create);
2429

2530
rules
2631
}
+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
use clap::builder::Str;
2+
use crate::linter::SolidFile;
3+
use crate::rules::types::*;
4+
use crate::types::*;
5+
use solc_wrapper::{ContractDefinitionChildNodes, ContractKind, decode_location, NodeType, SourceLocation, SourceUnit, SourceUnitChildNodes};
6+
7+
pub struct Ordering {
8+
data: RuleEntry
9+
}
10+
11+
#[derive(Debug)]
12+
pub struct Eval {
13+
weight: usize,
14+
src: SourceLocation
15+
}
16+
17+
fn eval_file(source_unit_childs: &Vec<SourceUnitChildNodes>) -> Vec<Eval>{
18+
19+
let mut eval = Vec::new();
20+
21+
for node in source_unit_childs {
22+
match node {
23+
SourceUnitChildNodes::ErrorDefinition(error) => {
24+
if error.node_type == NodeType::EnumDefinition {
25+
eval.push(Eval { weight: 1, src: error.src.clone() });
26+
} else if error.node_type == NodeType::StructDefinition {
27+
eval.push(Eval { weight: 2, src: error.src.clone() });
28+
}
29+
//TODO: Remove this when Error definition fixed
30+
}
31+
SourceUnitChildNodes::EnumDefinition(tmp) => eval.push(Eval { weight: 2, src: tmp.src.clone() }),
32+
SourceUnitChildNodes::StructDefinition(tmp) => eval.push(Eval { weight: 3, src: tmp.src.clone() }),
33+
SourceUnitChildNodes::ContractDefinition(contract) => {
34+
if contract.contract_kind == ContractKind::Interface {
35+
eval.push(Eval { weight: 3, src: contract.src.clone() });
36+
} else if contract.contract_kind == ContractKind::Library {
37+
eval.push(Eval { weight: 4, src: contract.src.clone() });
38+
} else {
39+
eval.push(Eval { weight: 5, src: contract.src.clone() });
40+
}
41+
}
42+
_ => { continue; }
43+
}
44+
}
45+
46+
eval
47+
}
48+
49+
fn eval_contract(contract_child_node: &Vec<ContractDefinitionChildNodes>) -> Vec<Eval>{
50+
51+
let mut eval = Vec::new();
52+
53+
for node in contract_child_node {
54+
match node {
55+
ContractDefinitionChildNodes::ErrorDefinition(tmp) => {
56+
//TODO: Remove this when Error definition fixed
57+
if tmp.node_type == NodeType::EnumDefinition {
58+
eval.push(Eval { weight: 3, src: tmp.src.clone() });
59+
} else if tmp.node_type == NodeType::StructDefinition {
60+
eval.push(Eval { weight: 2, src: tmp.src.clone() });
61+
}
62+
},
63+
ContractDefinitionChildNodes::UsingForDirective(tmp) => eval.push(Eval { weight: 1, src: tmp.src.clone() }),
64+
ContractDefinitionChildNodes::StructDefinition(tmp) => eval.push(Eval { weight: 2, src: tmp.src.clone() }),
65+
ContractDefinitionChildNodes::EnumDefinition(tmp) => eval.push(Eval { weight: 3, src: tmp.src.clone() }),
66+
ContractDefinitionChildNodes::VariableDeclaration(tmp) => eval.push(Eval { weight: 4, src: tmp.src.clone() }),
67+
ContractDefinitionChildNodes::EventDefinition(tmp) => eval.push(Eval { weight: 5, src: tmp.src.clone() }),
68+
ContractDefinitionChildNodes::ModifierDefinition(tmp) => eval.push(Eval { weight: 6, src: tmp.src.clone() }),
69+
ContractDefinitionChildNodes::FunctionDefinition(tmp) => eval.push(Eval { weight: 7, src: tmp.src.clone() }),
70+
_ => { continue; }
71+
}
72+
}
73+
74+
eval
75+
}
76+
77+
impl RuleType for Ordering {
78+
79+
fn diagnose(&self, file: &SolidFile, files: &Vec<SolidFile>) -> Vec<LintDiag> {
80+
81+
let mut res = Vec::new();
82+
let eval = eval_file(&file.data.nodes);
83+
84+
if eval.len() > 1 {
85+
for i in 0..eval.len() - 1 {
86+
if eval[i].weight > eval[i + 1].weight {
87+
let location = decode_location(&eval[i].src, &file.content);
88+
res.push(LintDiag {
89+
range: Range {
90+
start: Position { line: location.0.line as u64, character: location.0.column as u64 },
91+
end: Position { line: location.1.line as u64, character: location.1.column as u64 },
92+
length: location.0.length as u64,
93+
},
94+
message: format!("File need to be ordered: Using for -> Struct -> Enum -> Variable -> Event -> Modifier -> Function"),
95+
severity: Some(self.data.severity),
96+
code: None,
97+
source: None,
98+
uri: file.path.clone(),
99+
source_file_content: file.content.clone(),
100+
});
101+
}
102+
}
103+
}
104+
105+
for node in &file.data.nodes {
106+
match node {
107+
SourceUnitChildNodes::ContractDefinition(contract) => {
108+
let eval = eval_contract(&contract.nodes);
109+
110+
if eval.len() < 2 { continue; }
111+
for i in 0..eval.len() - 1 {
112+
if eval[i].weight > eval[i + 1].weight {
113+
let location = decode_location(&eval[i].src, &file.content);
114+
res.push(LintDiag {
115+
range: Range {
116+
start: Position { line: location.0.line as u64, character: location.0.column as u64 },
117+
end: Position { line: location.1.line as u64, character: location.1.column as u64 },
118+
length: location.0.length as u64,
119+
},
120+
message: format!("Contract need to be ordered: Enum -> Struct -> Interface -> Library -> Contract"),
121+
severity: Some(self.data.severity),
122+
code: None,
123+
source: None,
124+
uri: file.path.clone(),
125+
source_file_content: file.content.clone(),
126+
});
127+
}
128+
}
129+
}
130+
_ => {}
131+
}
132+
}
133+
134+
res
135+
}
136+
}
137+
138+
impl Ordering {
139+
pub(crate) fn create(data: RuleEntry) -> Box<dyn RuleType> {
140+
let mut rule = Ordering {
141+
data
142+
};
143+
Box::new(rule)
144+
}
145+
146+
pub(crate) fn create_default() -> RuleEntry {
147+
RuleEntry {
148+
id: "ordering".to_string(),
149+
severity: Severity::WARNING,
150+
data: vec![]
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)