UNPKG

solhint-community

Version:
133 lines (117 loc) 3.81 kB
const BaseChecker = require('../base-checker') const { contractWith } = require('../../../test/common/contract-builder') const { hasLeadingUnderscore } = require('../../common/identifier-naming') const { severityDescription } = require('../../doc/utils') const DEFAULT_SEVERITY = 'warn' const ruleId = 'non-state-vars-leading-underscore' const meta = { type: 'naming', docs: { description: 'Variables that are not in contract state should start with underscore. Conversely, variables that can cause an SLOAD/SSTORE should NOT start with an underscore. This makes it evident which operations cause expensive storage access when hunting for gas optimizations', category: 'Best Practice Rules', examples: { good: [ { description: 'mutable variable should NOT start with underscore since they DO cause storage read/writes', code: contractWith('uint256 public foo;'), }, { description: 'immutable variable should start with underscore since they do not cause storage reads', code: contractWith('uint256 immutable public _FOO;'), }, { description: 'block variable with leading underscore', code: contractWith('function foo() public { uint _myVar; }'), }, { description: 'function parameter with leading underscore', code: contractWith('function foo( uint256 _foo ) public {}'), }, ], bad: [ { description: 'mutable variable starting with underscore', code: contractWith('uint256 public _foo;'), }, { description: 'block variable without leading underscore', code: contractWith('function foo() public { uint myVar; }'), }, { description: 'function parameter without leading underscore', code: contractWith('function foo( uint256 foo ) public {}'), }, ], }, notes: [ { note: 'event & custom error parameters and struct memer names are ignored since they do not define variables', }, { note: 'this rule is contradictory with private-vars-leading-underscore, only one of them should be enabled at the same time.', }, ], options: [ { description: severityDescription, default: DEFAULT_SEVERITY, }, ], }, recommended: false, schema: null, defaultSetup: [DEFAULT_SEVERITY], } class NonStateVarsLeadingUnderscoreChecker extends BaseChecker { definingSubName = false constructor(reporter) { super(reporter, ruleId, meta) } FileLevelConstant(node) { this.validateName(node, true) } StructDefinition() { this.definingSubName = true } 'StructDefinition:exit'() { this.definingSubName = false } EventDefinition() { this.definingSubName = true } 'EventDefinition:exit'() { this.definingSubName = false } CustomErrorDefinition() { this.definingSubName = true } 'CustomErrorDefinition:exit'() { this.definingSubName = false } VariableDeclaration(node) { if (this.definingSubName) return if (node.isStateVar) { this.validateName(node, node.isDeclaredConst || node.isImmutable) } else { this.validateName(node, true) } } validateName(node, shouldHaveLeadingUnderscore) { if (node.name === null) { return } if (hasLeadingUnderscore(node.name) !== shouldHaveLeadingUnderscore) { this._error(node, node.name, shouldHaveLeadingUnderscore) } } _error(node, name, shouldHaveLeadingUnderscore) { this.error( node, `'${name}' ${shouldHaveLeadingUnderscore ? 'should' : 'should not'} start with _` ) } } module.exports = NonStateVarsLeadingUnderscoreChecker