0
# Rules System
1
2
Comprehensive rule system with 64+ rules across 7 categories for security, style, and best practices validation. The rules system is the core of Solhint's linting capabilities, providing extensive validation of Solidity code.
3
4
## Capabilities
5
6
### Main Rules Function
7
8
Creates and returns array of enabled rule checkers based on configuration.
9
10
```javascript { .api }
11
/**
12
* Creates and returns array of enabled rule checkers
13
* @param {Reporter} reporter - Reporter instance for collecting issues
14
* @param {Object} configVals - Configuration values
15
* @param {string} inputSrc - Source code being linted
16
* @param {Array} tokens - Parsed tokens
17
* @param {string} fileName - File name being processed
18
* @returns {Array} Array of enabled rule checker instances
19
*/
20
function checkers(reporter, configVals, inputSrc, tokens, fileName);
21
```
22
23
**Usage Examples:**
24
25
```javascript
26
const checkers = require('solhint/lib/rules/index');
27
const Reporter = require('solhint/lib/reporter');
28
29
// Create rule checkers (typically done internally)
30
const reporter = new Reporter([], {});
31
const config = { rules: { 'func-visibility': 'error' } };
32
const ruleCheckers = checkers(reporter, config, sourceCode, tokens, 'test.sol');
33
34
console.log(`Enabled rules: ${ruleCheckers.length}`);
35
```
36
37
## Rule Categories
38
39
### Security Rules (16 rules)
40
41
Rules focused on identifying potential security vulnerabilities and unsafe patterns.
42
43
**Key Rules:**
44
- `avoid-call-value` - Avoid using `.call.value()()`
45
- `avoid-low-level-calls` - Avoid low-level calls like `call`, `delegatecall`, `staticcall`
46
- `avoid-tx-origin` - Avoid using `tx.origin` for authorization
47
- `check-send-result` - Check result of `send()` calls
48
- `compiler-version` - Enforce specific compiler version constraints
49
- `func-visibility` - Require explicit function visibility declarations
50
- `reentrancy` - Detect potential reentrancy vulnerabilities
51
- `state-visibility` - Require explicit state variable visibility
52
53
**Configuration Examples:**
54
55
```javascript
56
{
57
"rules": {
58
"avoid-low-level-calls": "error",
59
"compiler-version": ["error", "^0.8.0"],
60
"func-visibility": "error",
61
"reentrancy": "warn"
62
}
63
}
64
```
65
66
### Naming Rules (13 rules)
67
68
Rules for enforcing consistent naming conventions across Solidity code.
69
70
**Key Rules:**
71
- `const-name-snakecase` - Constants in SCREAMING_SNAKE_CASE
72
- `contract-name-capwords` - Contracts, structs, enums in CapWords
73
- `event-name-capwords` - Events in CapWords
74
- `func-name-mixedcase` - Functions in mixedCase
75
- `modifier-name-mixedcase` - Modifiers in mixedCase
76
- `var-name-mixedcase` - Variables in mixedCase
77
- `private-vars-leading-underscore` - Private variables with leading underscore
78
79
**Configuration Examples:**
80
81
```javascript
82
{
83
"rules": {
84
"contract-name-capwords": "error",
85
"func-name-mixedcase": "error",
86
"var-name-mixedcase": "warn",
87
"private-vars-leading-underscore": ["error", { "strict": false }]
88
}
89
}
90
```
91
92
### Best Practices Rules (15 rules)
93
94
Rules promoting good coding practices, code quality, and maintainability.
95
96
**Key Rules:**
97
- `code-complexity` - Limit cyclomatic complexity
98
- `explicit-types` - Require or forbid explicit types (uint256 vs uint)
99
- `function-max-lines` - Limit function length
100
- `max-line-length` - Limit line length
101
- `no-console` - Forbid console.log statements
102
- `no-empty-blocks` - Forbid empty code blocks
103
- `no-global-import` - Require specific imports instead of global imports
104
- `no-unused-vars` - Detect unused variables
105
- `reason-string` - Require reason strings in require/revert statements
106
107
**Configuration Examples:**
108
109
```javascript
110
{
111
"rules": {
112
"code-complexity": ["warn", 7],
113
"function-max-lines": ["warn", 50],
114
"max-line-length": ["warn", 120],
115
"no-console": "error",
116
"reason-string": ["warn", { "maxLength": 64 }]
117
}
118
}
119
```
120
121
### Order Rules (4 rules)
122
123
Rules for code organization and element ordering within contracts.
124
125
**Key Rules:**
126
- `imports-on-top` - Import statements must be at file top
127
- `imports-order` - Enforce specific import ordering
128
- `ordering` - Enforce element ordering within contracts
129
- `visibility-modifier-order` - Visibility modifier must come first
130
131
**Configuration Examples:**
132
133
```javascript
134
{
135
"rules": {
136
"imports-on-top": "error",
137
"ordering": "warn",
138
"visibility-modifier-order": "error"
139
}
140
}
141
```
142
143
### Miscellaneous Rules (4 rules)
144
145
General utility rules for various code quality checks.
146
147
**Key Rules:**
148
- `comprehensive-interface` - Ensure interface completeness
149
- `duplicated-imports` - Prevent duplicate imports
150
- `import-path-check` - Validate import paths
151
- `quotes` - Enforce quote style consistency
152
153
**Configuration Examples:**
154
155
```javascript
156
{
157
"rules": {
158
"quotes": ["warn", "double"],
159
"duplicated-imports": "error"
160
}
161
}
162
```
163
164
### Deprecations Rules (1 rule)
165
166
Rules for identifying and migrating deprecated language features.
167
168
**Key Rules:**
169
- `constructor-syntax` - Use new constructor keyword syntax
170
171
### Gas Consumption Rules (11 rules)
172
173
Rules focused on gas optimization and efficient contract design.
174
175
**Key Rules:**
176
- `gas-calldata-parameters` - Use calldata for read-only function parameters
177
- `gas-custom-errors` - Use custom errors instead of string reasons
178
- `gas-indexed-events` - Use indexed event parameters appropriately
179
- `gas-length-in-loops` - Avoid repeated length calculations in loops
180
- `gas-struct-packing` - Optimize struct field packing
181
182
**Configuration Examples:**
183
184
```javascript
185
{
186
"rules": {
187
"gas-custom-errors": "warn",
188
"gas-indexed-events": ["warn", { "maxIndexed": 3 }],
189
"gas-length-in-loops": "warn"
190
}
191
}
192
```
193
194
## Rule Configuration Patterns
195
196
### Severity Levels
197
198
```javascript
199
{
200
"rules": {
201
"func-visibility": "error", // Block deployment
202
"max-line-length": "warn", // Show warning
203
"no-console": "off" // Disabled
204
}
205
}
206
```
207
208
### Rules with Options
209
210
Many rules accept configuration options:
211
212
```javascript
213
{
214
"rules": {
215
"compiler-version": ["error", "^0.8.0"],
216
"code-complexity": ["warn", 10],
217
"max-line-length": ["warn", 120],
218
"gas-indexed-events": ["warn", { "maxIndexed": 3 }],
219
"private-vars-leading-underscore": ["error", { "strict": true }]
220
}
221
}
222
```
223
224
### Built-in Rule Sets
225
226
```javascript
227
{
228
"extends": "solhint:recommended", // Recommended rules
229
// OR
230
"extends": "solhint:all", // All rules enabled
231
"rules": {
232
"no-console": "off" // Override specific rules
233
}
234
}
235
```
236
237
## Rule Implementation Structure
238
239
Each rule follows a consistent pattern:
240
241
```javascript { .api }
242
class RuleChecker {
243
constructor(reporter, config) {
244
this.reporter = reporter;
245
this.config = config;
246
this.ruleId = 'rule-name';
247
}
248
249
// Visit AST nodes
250
visitFunctionDefinition(node) {
251
// Check rule conditions
252
if (violatesRule(node)) {
253
this.reporter.error(node, this.ruleId, 'Error message');
254
}
255
}
256
}
257
```
258
259
**Rule Metadata:**
260
261
```javascript { .api }
262
class RuleChecker {
263
static get meta() {
264
return {
265
type: 'best-practices',
266
docs: {
267
description: 'Rule description',
268
category: 'Best Practices'
269
},
270
schema: {
271
type: 'object',
272
properties: {
273
maxLength: { type: 'integer' }
274
}
275
}
276
};
277
}
278
}
279
```
280
281
## Plugin System
282
283
Solhint supports external rule plugins:
284
285
```javascript
286
{
287
"plugins": ["prettier", "security"],
288
"rules": {
289
"prettier/prettier": "error",
290
"security/no-hardcoded-secrets": "warn"
291
}
292
}
293
```
294
295
**Plugin Structure:**
296
297
```javascript
298
// solhint-plugin-security/index.js
299
module.exports = [
300
require('./rules/no-hardcoded-secrets'),
301
require('./rules/safe-math-usage')
302
];
303
```
304
305
## Rule Execution Flow
306
307
1. **Initialization**: Rules are instantiated based on configuration
308
2. **AST Traversal**: Parser visits each AST node
309
3. **Rule Checking**: Matching rules inspect nodes and report issues
310
4. **Result Collection**: Reporter collects all issues
311
5. **Output Formatting**: Results are formatted for display
312
313
## Rule Development
314
315
Rules can be categorized by their inspection approach:
316
317
- **AST Node Visitors**: Inspect specific node types (functions, variables, etc.)
318
- **Token Analyzers**: Examine raw token sequences
319
- **Source Code Processors**: Analyze source text directly
320
- **Cross-Reference Checkers**: Track relationships between code elements
321
322
## Error Handling in Rules
323
324
Rules should handle edge cases gracefully:
325
326
```javascript
327
visitFunctionDefinition(node) {
328
try {
329
// Rule logic
330
if (node.body && node.body.statements) {
331
// Process statements
332
}
333
} catch (error) {
334
// Log but don't crash
335
console.warn(`Rule ${this.ruleId} failed:`, error.message);
336
}
337
}
338
```
339
340
## Rule Performance
341
342
- Rules execute during AST traversal, so efficiency matters
343
- Cache expensive computations when possible
344
- Avoid deep object traversals in hot paths
345
- Use early returns to skip unnecessary processing