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