diff --git a/e2e/08-autofix/explicit-types/Foo1.sol b/e2e/08-autofix/explicit-types/Foo1.sol index 78bcaec7..8581c416 100644 --- a/e2e/08-autofix/explicit-types/Foo1.sol +++ b/e2e/08-autofix/explicit-types/Foo1.sol @@ -1,22 +1,95 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.4; +pragma solidity ^0.8.0; -import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol'; +contract ExplicitTypes { + uint256 public varUint256_1; + uint256 public varUint256_2 = uint256(1); -contract Foo1 is ERC20Burnable { - uint public hola; - uint public hola2; - int public constant hola3 = 2; - ufixed hola4; - fixed internal hola5; + uint public varUint_1; + uint public varUint_2 = uint(1); - constructor() ERC20('MyToken', 'MTK') {} + int256 public varInt256; + int public varInt; - // solhint-disable no-empty-blocks - function payableTrue() public payable {} + ufixed128x18 public varUfixed128x18; + ufixed public varUfixed; + fixed128x18 public varFixed128x18; + fixed public varFixed; - // solhint-disable no-empty-blocks - function payableFalse() public {} - function zarasa() {} + event EventWithInt256(int256 varWithInt256, address addressVar, bool boolVat, int varWithInt); + + mapping(uint256 => fixed128x18) public mapWithFixed128x18_1; + + mapping(uint => fixed128x18) public mapWithFixed128x18_2; + + mapping(uint => mapping(fixed128x18 => int256)) mapOfMap; + + mapping(uint256 => Estructura[]) mapOfArrayStructWithMap; + + struct Estructura1 { + ufixed128x18 varWithUfixed128x18; + uint varUint; + } + + struct Estructura2 { + ufixed128x18 varWithUfixed128x18; + uint varUint; + mapping(uint256 => Estructura) mapOfStruct; + } + + struct Estructura3 { + ufixed varWithUfixed; + uint varUint; + mapping(address => uint256) structWithMap; + } + + struct Estructura4 { + ufixed varWithUfixed; + uint varUint; + mapping(address => uint256) structWithMap; + } + + + uint256[] public arr1; + + uint[] public arr2 = [1,2,3]; + + uint[] public arr3 = [uint(1),2,3]; + + uint256[] public arr4 = [[1,2,3]]; + + uint[] public arr5 = [1,2,3]; + + mapping(uint256 => arr5) mapOfFixedArray; + + modifier withUint256() { + _; + uint256 varUint; + varUint = uint256(1); + + } + + constructor() {} + + function withUint256_1(uint256 varUint256, uint varUint) public returns(int256 returnInt256) {} + + function withUint256_2(uint varUint, uint varUint) public returns(int returnInt) {} + + function withUint256_3() external { + uint256 varUint256 = uint256(1); + } + + function withUint256_4() external { + uint256 varUint; + varUint = uint256(1); + } + + function withUint_1() external { + uint varUint = uint(1); + } + + function withUint_2() external { + uint varUint; varUint = uint(1); + } } diff --git a/e2e/08-autofix/explicit-types/Foo1AfterFix.sol b/e2e/08-autofix/explicit-types/Foo1AfterFix.sol index ca900d69..17b90cda 100644 --- a/e2e/08-autofix/explicit-types/Foo1AfterFix.sol +++ b/e2e/08-autofix/explicit-types/Foo1AfterFix.sol @@ -1,22 +1,95 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.4; +pragma solidity ^0.8.0; -import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol'; +contract ExplicitTypes { + uint256 public varUint256_1; + uint256 public varUint256_2 = uint256(1); -contract Foo1 is ERC20Burnable { - uint256 public hola; - uint256 public hola2; - int256 public constant hola3 = 2; - ufixed128x18 hola4; - fixed128x18 internal hola5; + uint256 public varUint_1; + uint256 public varUint_2 = uint256(1); - constructor() ERC20('MyToken', 'MTK') {} + int256 public varInt256; + int256 public varInt; - // solhint-disable no-empty-blocks - function payableTrue() public payable {} + ufixed128x18 public varUfixed128x18; + ufixed128x18 public varUfixed; + fixed128x18 public varFixed128x18; + fixed128x18 public varFixed; - // solhint-disable no-empty-blocks - function payableFalse() public {} - function zarasa() {} + event EventWithInt256(int256 varWithInt256, address addressVar, bool boolVat, int256 varWithInt); + + mapping(uint256 => fixed128x18) public mapWithFixed128x18_1; + + mapping(uint256 => fixed128x18) public mapWithFixed128x18_2; + + mapping(uint256 => mapping(fixed128x18 => int256)) mapOfMap; + + mapping(uint256 => Estructura[]) mapOfArrayStructWithMap; + + struct Estructura1 { + ufixed128x18 varWithUfixed128x18; + uint256 varUint; + } + + struct Estructura2 { + ufixed128x18 varWithUfixed128x18; + uint256 varUint; + mapping(uint256 => Estructura) mapOfStruct; + } + + struct Estructura3 { + ufixed128x18 varWithUfixed; + uint256 varUint; + mapping(address => uint256) structWithMap; + } + + struct Estructura4 { + ufixed128x18 varWithUfixed; + uint256 varUint; + mapping(address => uint256) structWithMap; + } + + + uint256[] public arr1; + + uint256[] public arr2 = [1,2,3]; + + uint256[] public arr3 = [uint256(1),2,3]; + + uint256[] public arr4 = [[1,2,3]]; + + uint256[] public arr5 = [1,2,3]; + + mapping(uint256 => arr5) mapOfFixedArray; + + modifier withUint256() { + _; + uint256 varUint; + varUint = uint256(1); + + } + + constructor() {} + + function withUint256_1(uint256 varUint256, uint256 varUint) public returns(int256 returnInt256) {} + + function withUint256_2(uint256 varUint, uint256 varUint) public returns(int256 returnInt) {} + + function withUint256_3() external { + uint256 varUint256 = uint256(1); + } + + function withUint256_4() external { + uint256 varUint; + varUint = uint256(1); + } + + function withUint_1() external { + uint256 varUint = uint256(1); + } + + function withUint_2() external { + uint256 varUint; varUint = uint256(1); + } } diff --git a/e2e/08-autofix/explicit-types/Foo1BeforeFix.sol b/e2e/08-autofix/explicit-types/Foo1BeforeFix.sol index 78bcaec7..8581c416 100644 --- a/e2e/08-autofix/explicit-types/Foo1BeforeFix.sol +++ b/e2e/08-autofix/explicit-types/Foo1BeforeFix.sol @@ -1,22 +1,95 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.4; +pragma solidity ^0.8.0; -import {ERC20Burnable} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol'; +contract ExplicitTypes { + uint256 public varUint256_1; + uint256 public varUint256_2 = uint256(1); -contract Foo1 is ERC20Burnable { - uint public hola; - uint public hola2; - int public constant hola3 = 2; - ufixed hola4; - fixed internal hola5; + uint public varUint_1; + uint public varUint_2 = uint(1); - constructor() ERC20('MyToken', 'MTK') {} + int256 public varInt256; + int public varInt; - // solhint-disable no-empty-blocks - function payableTrue() public payable {} + ufixed128x18 public varUfixed128x18; + ufixed public varUfixed; + fixed128x18 public varFixed128x18; + fixed public varFixed; - // solhint-disable no-empty-blocks - function payableFalse() public {} - function zarasa() {} + event EventWithInt256(int256 varWithInt256, address addressVar, bool boolVat, int varWithInt); + + mapping(uint256 => fixed128x18) public mapWithFixed128x18_1; + + mapping(uint => fixed128x18) public mapWithFixed128x18_2; + + mapping(uint => mapping(fixed128x18 => int256)) mapOfMap; + + mapping(uint256 => Estructura[]) mapOfArrayStructWithMap; + + struct Estructura1 { + ufixed128x18 varWithUfixed128x18; + uint varUint; + } + + struct Estructura2 { + ufixed128x18 varWithUfixed128x18; + uint varUint; + mapping(uint256 => Estructura) mapOfStruct; + } + + struct Estructura3 { + ufixed varWithUfixed; + uint varUint; + mapping(address => uint256) structWithMap; + } + + struct Estructura4 { + ufixed varWithUfixed; + uint varUint; + mapping(address => uint256) structWithMap; + } + + + uint256[] public arr1; + + uint[] public arr2 = [1,2,3]; + + uint[] public arr3 = [uint(1),2,3]; + + uint256[] public arr4 = [[1,2,3]]; + + uint[] public arr5 = [1,2,3]; + + mapping(uint256 => arr5) mapOfFixedArray; + + modifier withUint256() { + _; + uint256 varUint; + varUint = uint256(1); + + } + + constructor() {} + + function withUint256_1(uint256 varUint256, uint varUint) public returns(int256 returnInt256) {} + + function withUint256_2(uint varUint, uint varUint) public returns(int returnInt) {} + + function withUint256_3() external { + uint256 varUint256 = uint256(1); + } + + function withUint256_4() external { + uint256 varUint; + varUint = uint256(1); + } + + function withUint_1() external { + uint varUint = uint(1); + } + + function withUint_2() external { + uint varUint; varUint = uint(1); + } } diff --git a/e2e/autofix-test.js b/e2e/autofix-test.js index ae2c82d9..8a6ad611 100644 --- a/e2e/autofix-test.js +++ b/e2e/autofix-test.js @@ -181,7 +181,7 @@ describe('e2e', function () { it('should get the right report (2)', () => { const reportLines = stdout.split('\n') - const finalLine = '5 problems (5 errors, 0 warnings)' + const finalLine = '27 problems (27 errors, 0 warnings)' expect(reportLines[reportLines.length - 3]).to.contain(finalLine) }) }) diff --git a/lib/rules/best-practises/explicit-types.js b/lib/rules/best-practises/explicit-types.js index 3273b340..217132c2 100644 --- a/lib/rules/best-practises/explicit-types.js +++ b/lib/rules/best-practises/explicit-types.js @@ -7,6 +7,7 @@ const ALL_TYPES = EXPLICIT_TYPES.concat(IMPLICIT_TYPES) const VALID_CONFIGURATION_OPTIONS = ['explicit', 'implicit'] const DEFAULT_OPTION = 'explicit' const DEFAULT_SEVERITY = 'warn' +const alreadyFixedRanges = [] let typesToSearch const ruleId = 'explicit-types' @@ -137,15 +138,6 @@ class ExplicitTypesChecker extends BaseChecker { } } - fixStatement(typeNameNode, errorVar) { - const configFileIndex = typesToSearch.findIndex((arg) => arg === errorVar) - return (fixer) => - fixer.replaceTextRange( - typeNameNode.typeName.range, - this.isExplicit ? EXPLICIT_TYPES[configFileIndex] : IMPLICIT_TYPES[configFileIndex] - ) - } - findNamesOfElementaryTypeName(jsonObject, typeToFind) { const names = [] @@ -164,6 +156,53 @@ class ExplicitTypesChecker extends BaseChecker { searchInObject(jsonObject) return names } + + findTypeRanges(node, typeToSearch, results = []) { + // Check if the current node is an object + if (typeof node === 'object' && node !== null) { + // Check if the current node matches the criteria + if (node.type === 'ElementaryTypeName' && node.name === typeToSearch) { + // If it matches, push its range to the results array + results.push(node.range) + } + // Recursively search through all properties of the object + Object.values(node).forEach((value) => { + // If the value is an object or an array, search it recursively + if (typeof value === 'object') { + this.findTypeRanges(value, typeToSearch, results) + } + }) + } else if (Array.isArray(node)) { + // If the current node is an array, search each element + node.forEach((item) => this.findTypeRanges(item, typeToSearch, results)) + } + return results + } + + fixStatement(node, errorVar) { + const range = this.findTypeRanges(node, errorVar) + + // previous script searches all json and if two uint/uint256/ufixed/etc are in the same line + // it will return two set of range values + // this is to remove the first one if it's already been corrected + // and to push it to the array to store the corrected ones + if (alreadyFixedRanges.includes(range[0])) { + range.shift() + } + alreadyFixedRanges.push(range[0]) + + // only check the first range returned when findTypesRanges return two or more + const charsToReplace = errorVar.length - 1 + range[0][1] = range[0][0] + charsToReplace + + const configFileIndex = typesToSearch.findIndex((arg) => arg === errorVar) + + return (fixer) => + fixer.replaceTextRange( + range[0], + this.isExplicit ? EXPLICIT_TYPES[configFileIndex] : IMPLICIT_TYPES[configFileIndex] + ) + } } module.exports = ExplicitTypesChecker diff --git a/test/rules/best-practises/explicit-types.js b/test/rules/best-practises/explicit-types.js index 2ff4a296..bdfebd3a 100644 --- a/test/rules/best-practises/explicit-types.js +++ b/test/rules/best-practises/explicit-types.js @@ -66,7 +66,7 @@ describe('Linter - explicit-types rule', () => { const { zeroErrorsImplicit, zeroErrorsExplicit } = getZeroErrosObject() for (const key in zeroErrorsExplicit) { - it(`should NOT raise error for ${key} on 'implicit' mode`, () => { + it(`should NOT raise error for ${key} on 'explicit' mode`, () => { const { code } = zeroErrorsExplicit[key] const report = linter.processStr(contractWith(code), { rules: { 'explicit-types': ['error', 'explicit'] },