-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #545 from protofire/gc-increment-by-one
GC: Increment by one
- Loading branch information
Showing
15 changed files
with
320 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
--- | ||
warning: "This is a dynamically generated file. Do not edit manually." | ||
layout: "default" | ||
title: "gas-increment-by-one | Solhint" | ||
--- | ||
|
||
# gas-increment-by-one | ||
 | ||
 | ||
|
||
## Description | ||
Suggest incrementation by one like this ++i instead of other type | ||
|
||
## Options | ||
This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Default to warn. | ||
|
||
### Example Config | ||
```json | ||
{ | ||
"rules": { | ||
"gas-increment-by-one": "warn" | ||
} | ||
} | ||
``` | ||
|
||
### Notes | ||
- This rule only works for expressions like this: [ j = j + 1 ] but will fail is the code is written like this: [ j = 1 + j ] | ||
- [source 1](https://coinsbench.com/comprehensive-guide-tips-and-tricks-for-gas-optimization-in-solidity-5380db734404) of the rule initiative (Incrementing/Decrementing By 1) | ||
- [source 2](https://www.rareskills.io/post/gas-optimization?postId=c9db474a-ff97-4fa3-a51d-fe13ccb8fe3b#viewer-8rekj) of the rule initiative | ||
|
||
## Examples | ||
This rule does not have examples. | ||
|
||
## Version | ||
This rule is introduced in the latest version. | ||
|
||
## Resources | ||
- [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/gas-consumption/gas-increment-by-one.js) | ||
- [Document source](https://github.com/protofire/solhint/tree/master/docs/rules/gas-consumption/gas-increment-by-one.md) | ||
- [Test cases](https://github.com/protofire/solhint/tree/master/test/rules/gas-consumption/gas-increment-by-one.js) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
/* eslint-disable */ | ||
const { isArray } = require('lodash') | ||
const BaseChecker = require('../base-checker') | ||
|
||
const operators = ['+', '-', '++', '--'] | ||
const binaryOperators = ['+', '-', '+=', '-='] | ||
|
||
const ruleId = 'gas-increment-by-one' | ||
const meta = { | ||
type: 'gas-consumption', | ||
|
||
docs: { | ||
description: 'Suggest incrementation by one like this ++i instead of other type', | ||
category: 'Gas Consumption Rules', | ||
notes: [ | ||
{ | ||
note: 'This rule only works for expressions like this: [ j = j + 1 ] but will fail is the code is written like this: [ j = 1 + j ]', | ||
}, | ||
{ | ||
note: '[source 1](https://coinsbench.com/comprehensive-guide-tips-and-tricks-for-gas-optimization-in-solidity-5380db734404) of the rule initiative (Incrementing/Decrementing By 1)', | ||
}, | ||
{ | ||
note: '[source 2](https://www.rareskills.io/post/gas-optimization?postId=c9db474a-ff97-4fa3-a51d-fe13ccb8fe3b#viewer-8rekj) of the rule initiative', | ||
}, | ||
], | ||
}, | ||
|
||
isDefault: false, | ||
recommended: false, | ||
defaultSetup: 'warn', | ||
|
||
schema: null, | ||
} | ||
|
||
class GasIncrementByOne extends BaseChecker { | ||
constructor(reporter) { | ||
super(reporter, ruleId, meta) | ||
} | ||
|
||
UnaryOperation(node) { | ||
if (node.isPrefix) { | ||
// Ignore pre-increment and pre-decrement | ||
return | ||
} | ||
|
||
if (node.operator === '++' || node.operator === '--') { | ||
const variableName = this.extractVariableName(node.subExpression) | ||
if (variableName) { | ||
this.reportError(node, variableName) | ||
} | ||
} | ||
} | ||
|
||
BinaryOperation(node) { | ||
if (node.operator === '=' || node.operator === '+=' || node.operator === '-=') { | ||
const resultObject = this.isVariableIncrementOrDecrement(node.left, node.right, node.operator) | ||
if (resultObject.result) { | ||
this.reportError(node, resultObject.varName) | ||
} | ||
} | ||
} | ||
|
||
isVariableIncrementOrDecrement(left, right, operator) { | ||
const leftVar = this.extractVariableName(left) | ||
let rightValue | ||
|
||
// asignment and operation | ||
if (operator === '+=' || operator === '-=') { | ||
rightValue = right.type === 'NumberLiteral' && parseInt(right.number) === 1 | ||
return { result: leftVar && rightValue, varName: leftVar } | ||
} | ||
// regular asignment | ||
else if (operator === '=') { | ||
const rightVar = this.extractVariableName(right.left) | ||
rightValue = | ||
right.right && right.right.type === 'NumberLiteral' && parseInt(right.right.number) === 1 | ||
return { result: leftVar === rightVar && rightValue, varName: leftVar } | ||
} | ||
|
||
return false | ||
} | ||
|
||
extractVariableName(node) { | ||
if (node.type === 'Identifier') { | ||
return node.name | ||
} else if (node.type === 'MemberAccess') { | ||
return this.extractVariableName(node.expression) + '.' + node.memberName | ||
} else if (node.type === 'IndexAccess') { | ||
return this.extractVariableName(node.base) | ||
} | ||
return null | ||
} | ||
|
||
reportError(node, fullVariableName) { | ||
const variableName = fullVariableName.split('.')[0] | ||
this.error( | ||
node, | ||
`GC: For [ ${variableName} ] variable, increment/decrement by 1 using: [ ++variable ] to save gas` | ||
) | ||
} | ||
} | ||
|
||
module.exports = GasIncrementByOne | ||
|
||
// SourceUnit(node) { | ||
// this.findVariableUpdates(node) | ||
// } | ||
|
||
// findVariableUpdates(node) { | ||
// if (node === null || typeof node !== 'object') { | ||
// return | ||
// } | ||
|
||
// // Check for assignment in a function body | ||
// if (node.type === 'FunctionDefinition') { | ||
// this.findVariableUpdates(node.body) | ||
// return | ||
// } | ||
|
||
// if (node.type === 'ExpressionStatement' && node.expression.type === 'BinaryOperation') { | ||
// const expr = node.expression | ||
// if (expr.operator === '=' || expr.operator === '+=' || expr.operator === '-=') { | ||
// if (this.isVariableIncrementOrDecrement(expr.left, expr.right, expr.operator)) { | ||
// this.reportError(node, this.extractVariableName(expr.left)) | ||
// } | ||
// } | ||
// } | ||
|
||
// Object.values(node).forEach((value) => { | ||
// if (typeof value === 'object') { | ||
// this.findVariableUpdates(value) | ||
// } | ||
// }) | ||
// } | ||
|
||
// isVariableIncrementOrDecrement(left, right, operator) { | ||
// const leftVar = this.extractVariableName(left) | ||
// let rightVar, rightValue | ||
|
||
// if (operator === '+=' || operator === '-=') { | ||
// // For compound assignment, the operation is directly on the variable | ||
// rightValue = right.type === 'NumberLiteral' && parseInt(right.number) === 1 | ||
// return leftVar && rightValue | ||
// } else if (operator === '=') { | ||
// rightVar = this.extractVariableName(right.left) | ||
// rightValue = | ||
// right.right && right.right.type === 'NumberLiteral' && parseInt(right.right.number) === 1 | ||
// return leftVar === rightVar && rightValue | ||
// } | ||
|
||
// return false | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.