Skip to content

Commit 5c99a28

Browse files
authored
removing parentheses from modifiers with an empty list of parameters. (#555)
1 parent 375bd63 commit 5c99a28

File tree

11 files changed

+134
-21
lines changed

11 files changed

+134
-21
lines changed

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,34 @@ As a final check, make sure that VSCode is configured to format files on save.
277277

278278
Note: By design, Prettier prioritizes a local over a global configuration. If you have a `.prettierrc` file in your porject, your VSCode's default settings or rules in `settings.json` are ignored ([prettier/prettier-vscode#1079](https://github.com/prettier/prettier-vscode/issues/1079)).
279279

280+
## Edge cases
281+
282+
Prettier Solidity does its best to be pretty and consistent, but in some cases it falls back to doing things that are less than ideal.
283+
284+
### Modifiers in constructors
285+
286+
Modifiers with no arguments are formatted with their parentheses removed, except for constructors. The reason for this is that Prettier Solidity cannot always tell apart a modifier from a base constructor. So modifiers in constructors are not modified. For example, this:
287+
288+
```solidity
289+
contract Foo is Bar {
290+
constructor() Bar() modifier1 modifier2() modifier3(42) {}
291+
292+
function f() modifier1 modifier2() modifier3(42) {}
293+
}
294+
```
295+
296+
will be formatted as
297+
298+
```solidity
299+
contract Foo is Bar {
300+
constructor() Bar() modifier1 modifier2() modifier3(42) {}
301+
302+
function f() modifier1 modifier2 modifier3(42) {}
303+
}
304+
```
305+
306+
Notice that the unnecessary parentheses in `modifier2` were removed in the function but not in the constructor.
307+
280308
## Contributing
281309

282310
1. [Fork it](https://github.com/prettier-solidity/prettier-plugin-solidity/fork)

src/nodes/ModifierDefinition.js

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,23 @@ const {
77
const printSeparatedList = require('./print-separated-list');
88

99
const modifierParameters = (node, path, print) => {
10-
if (node.parameters) {
11-
return node.parameters.length > 0
12-
? [
13-
'(',
14-
printSeparatedList(path.map(print, 'parameters'), {
15-
separator: [
16-
',',
17-
// To keep consistency any list of parameters will split if it's longer than 2.
18-
// For more information see:
19-
// https://github.com/prettier-solidity/prettier-plugin-solidity/issues/256
20-
node.parameters.length > 2 ? hardline : line
21-
]
22-
}),
23-
')'
10+
if (node.parameters && node.parameters.length > 0) {
11+
return [
12+
'(',
13+
printSeparatedList(path.map(print, 'parameters'), {
14+
separator: [
15+
',',
16+
// To keep consistency any list of parameters will split if it's longer than 2.
17+
// For more information see:
18+
// https://github.com/prettier-solidity/prettier-plugin-solidity/issues/256
19+
node.parameters.length > 2 ? hardline : line
2420
]
25-
: '()';
21+
}),
22+
')'
23+
];
2624
}
2725

28-
return '';
26+
return '()';
2927
};
3028

3129
const virtual = (node) => (node.isVirtual ? [line, 'virtual'] : '');

src/nodes/ModifierInvocation.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ const printSeparatedList = require('./print-separated-list');
22

33
const modifierArguments = (node, path, print) => {
44
if (node.arguments) {
5+
// We always print parentheses at this stage because the parser already
6+
// stripped them in FunctionDefinitions that are not a constructor.
57
return node.arguments.length > 0
68
? ['(', printSeparatedList(path.map(print, 'arguments')), ')']
79
: '()';

src/parser.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,21 @@ function parse(text, _parsers, options) {
4343
);
4444
}
4545
},
46+
ModifierDefinition(ctx) {
47+
if (!ctx.parameters) {
48+
ctx.parameters = [];
49+
}
50+
},
51+
FunctionDefinition(ctx) {
52+
if (!ctx.isConstructor) {
53+
ctx.modifiers.forEach((modifier) => {
54+
if (modifier.arguments && modifier.arguments.length === 0) {
55+
// eslint-disable-next-line no-param-reassign
56+
modifier.arguments = null;
57+
}
58+
});
59+
}
60+
},
4661
ForStatement(ctx) {
4762
if (ctx.initExpression) {
4863
ctx.initExpression.omitSemicolon = true;

tests/config/format-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const testsWithAstChanges = new Map(
6161
"Parentheses/BitXorNoParentheses.sol",
6262
"Parentheses/LogicNoParentheses.sol",
6363
"HexLiteral/HexLiteral.sol",
64+
"ModifierInvocations/ModifierInvocations.sol",
6465
].map((fixture) => {
6566
const [file, compareBytecode = () => true] = Array.isArray(fixture)
6667
? fixture

tests/format/AllSolidityFeatures/__snapshots__/jsfmt.spec.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ contract DualIndex {
750750
mapping(uint256 => mapping(uint256 => uint256)) data;
751751
address public admin;
752752
753-
modifier restricted {
753+
modifier restricted() {
754754
if (msg.sender == admin) _;
755755
}
756756

tests/format/FunctionDefinitions/FunctionDefinitions.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ interface FunctionInterfaces {
99

1010
function manyParams(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10);
1111

12-
function manyModifiers() modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10;
12+
function manyModifiers() modifier1() modifier2() modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10;
1313

1414
function manyReturns() returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10);
1515

16-
function someParamsSomeModifiers(uint x1, uint x2, uint x3) modifier1 modifier2 modifier3;
16+
function someParamsSomeModifiers(uint x1, uint x2, uint x3) modifier1() modifier2 modifier3;
1717

1818
function someParamsSomeReturns(uint x1, uint x2, uint x3) returns(uint y1, uint y2, uint y3);
1919

tests/format/FunctionDefinitions/__snapshots__/jsfmt.spec.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ interface FunctionInterfaces {
1717
1818
function manyParams(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10);
1919
20-
function manyModifiers() modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10;
20+
function manyModifiers() modifier1() modifier2() modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10;
2121
2222
function manyReturns() returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10);
2323
24-
function someParamsSomeModifiers(uint x1, uint x2, uint x3) modifier1 modifier2 modifier3;
24+
function someParamsSomeModifiers(uint x1, uint x2, uint x3) modifier1() modifier2 modifier3;
2525
2626
function someParamsSomeReturns(uint x1, uint x2, uint x3) returns(uint y1, uint y2, uint y3);
2727
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.6;
3+
4+
contract ModifierDefinitions {
5+
// We enforce the use of parentheses in modifiers without parameters.
6+
modifier emptyParams {_;}
7+
modifier noParams() {_;}
8+
}
9+
10+
contract ModifierInvocations is ModifierDefinitions {
11+
// We can't differentiate between constructor calls or modifiers, so we keep
12+
// parentheses untouched in constructors.
13+
constructor () emptyParams noParams() ModifierDefinitions() {}
14+
15+
// We remove parentheses in modifiers without arguments.
16+
function test() public emptyParams noParams() {}
17+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`ModifierInvocations.sol format 1`] = `
4+
====================================options=====================================
5+
parsers: ["solidity-parse"]
6+
printWidth: 80
7+
| printWidth
8+
=====================================input======================================
9+
// SPDX-License-Identifier: MIT
10+
pragma solidity 0.8.6;
11+
12+
contract ModifierDefinitions {
13+
// We enforce the use of parentheses in modifiers without parameters.
14+
modifier emptyParams {_;}
15+
modifier noParams() {_;}
16+
}
17+
18+
contract ModifierInvocations is ModifierDefinitions {
19+
// We can't differentiate between constructor calls or modifiers, so we keep
20+
// parentheses untouched in constructors.
21+
constructor () emptyParams noParams() ModifierDefinitions() {}
22+
23+
// We remove parentheses in modifiers without arguments.
24+
function test() public emptyParams noParams() {}
25+
}
26+
27+
=====================================output=====================================
28+
// SPDX-License-Identifier: MIT
29+
pragma solidity 0.8.6;
30+
31+
contract ModifierDefinitions {
32+
// We enforce the use of parentheses in modifiers without parameters.
33+
modifier emptyParams() {
34+
_;
35+
}
36+
modifier noParams() {
37+
_;
38+
}
39+
}
40+
41+
contract ModifierInvocations is ModifierDefinitions {
42+
// We can't differentiate between constructor calls or modifiers, so we keep
43+
// parentheses untouched in constructors.
44+
constructor() emptyParams noParams() ModifierDefinitions() {}
45+
46+
// We remove parentheses in modifiers without arguments.
47+
function test() public emptyParams noParams {}
48+
}
49+
50+
================================================================================
51+
`;

0 commit comments

Comments
 (0)