diff --git a/lib/rules/order/ordering.js b/lib/rules/order/ordering.js index 494f3ad5..6d0e8a07 100644 --- a/lib/rules/order/ordering.js +++ b/lib/rules/order/ordering.js @@ -122,6 +122,13 @@ function sourceUnitPartOrder(node) { throw new Error('Unrecognized source unit part, please report this issue') } +function isInitializerModifier(modifiers, targetName, targetArguments) { + // search the modifiers array with the name === 'initializer' + return modifiers.some( + (modifier) => modifier.name === targetName && modifier.arguments === targetArguments + ) +} + function contractPartOrder(node) { if (node.type === 'UsingForDeclaration') { return [0, 'using for declaration'] @@ -154,8 +161,13 @@ function contractPartOrder(node) { return [40, 'modifier definition'] } - if (node.isConstructor) { - return [50, 'constructor'] + if ( + node.isConstructor || + (node.type === 'FunctionDefinition' && + node.name === 'initialize' && + isInitializerModifier(node.modifiers, 'initializer', null)) + ) { + return [50, 'constructor/initializer'] } if (isReceiveFunction(node)) { diff --git a/test/rules/order/ordering.js b/test/rules/order/ordering.js index d83d73f4..1ff356ef 100644 --- a/test/rules/order/ordering.js +++ b/test/rules/order/ordering.js @@ -427,4 +427,63 @@ describe('Linter - ordering', () => { assert.equal(report.errorCount, 0) }) + + it('should raise error when INITIALIZER is NOT well located', () => { + const code = ` + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.0; + import "@openzeppelin/contracts/ownership/Ownable.sol"; + uint256 constant oneNiceConstant = 1; + struct OneNiceStruct { uint256 a; uint256 b; } + enum MyEnum { A, B } + error Unauthorized(); + function freeFunction() pure returns (uint256) { + return 1; + } + contract OneNiceContract { + function initialize() initializer { + oneNiceConstant; + } + struct OneNiceStruct { uint256 a; uint256 b; } + } + ` + + const report = linter.processStr(code, { + rules: { ordering: 'error' }, + }) + + assert.equal(report.errorCount, 1) + assert.ok( + report.messages[0].message.includes( + 'Function order is incorrect, struct definition can not go after constructor/initializer' + ) + ) + }) + + it('should NOT raise error when INITIALIZER is well located', () => { + const code = ` + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.0; + import "@openzeppelin/contracts/ownership/Ownable.sol"; + uint256 constant oneNiceConstant = 1; + enum MyEnum { A, B } + struct OneNiceStruct { uint256 a; uint256 b; } + error Unauthorized(); + function freeFunction() pure returns (uint256) { + return 1; + } + contract OneNiceContract { + struct OneNiceStruct { uint256 a; uint256 b; } + function initialize() initializer { + oneNiceConstant; + } + } + ` + + const report = linter.processStr(code, { + rules: { ordering: 'error' }, + }) + + assert.equal(report.errorCount, 0) + }) })