Skip to content
Merged
41 changes: 38 additions & 3 deletions crates/config/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ pub struct FormatterConfig {
pub sort_imports: bool,
/// Whether to suppress spaces around the power operator (`**`).
pub pow_no_space: bool,
/// Whether to compact call args in a single line when possible
pub call_compact_args: bool,
/// Style that determines if a broken list, should keep its elements together on their own
/// line, before breaking individually.
pub prefer_compact: PreferCompact,
}

/// Style of integer types.
Expand Down Expand Up @@ -186,6 +187,40 @@ impl MultilineFuncHeaderStyle {
}
}

/// Style that determines if a broken list, should keep its elements together on their own line,
/// before breaking individually.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PreferCompact {
/// All elements are preferred consistent.
None,
/// Calls are preferred compact. Events and errors break consistently.
Calls,
/// Events are preferred compact. Calls and errors break consistently.
Events,
/// Errors are preferred compact. Calls and events break consistently.
Errors,
/// Events and errors are preferred compact. Calls break consistently.
EventsErrors,
/// All elements are preferred compact.
#[default]
All,
}

impl PreferCompact {
pub fn calls(&self) -> bool {
matches!(self, Self::All | Self::Calls)
}

pub fn events(&self) -> bool {
matches!(self, Self::All | Self::Events | Self::EventsErrors)
}

pub fn errors(&self) -> bool {
matches!(self, Self::All | Self::Errors | Self::EventsErrors)
}
}

/// Style of indent
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -214,7 +249,7 @@ impl Default for FormatterConfig {
contract_new_lines: false,
sort_imports: false,
pow_no_space: false,
call_compact_args: true,
prefer_compact: PreferCompact::default(),
docs_style: DocCommentStyle::default(),
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/fmt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ The formatter supports multiple configuration options defined in `foundry.toml`.
| `bracket_spacing` | `false` | Print spaces between brackets. |
| `int_types` | `long` | Style for `uint256`/`int256` types. Options: `long`, `short`, `preserve`. |
| `multiline_func_header` | `attributes_first` | The style of multiline function headers. Options: `attributes_first`, `params_always`, `params_first_multi`, `all`, `all_params`. |
| `prefer_compact` | `calls` | Style that determines if a broken list, should keep its elements together on their own line, before breaking individually. Options: `calls`, `events`, `errors`, `events_errors`, `all`. |
| `quote_style` | `double` | The style of quotation marks. Options: `double`, `single`, `preserve`. |
| `number_underscore` | `preserve` | The style of underscores in number literals. Options: `preserve`, `remove`, `thousands`. |
| `hex_underscore` | `remove` | The style of underscores in hex literals. Options: `preserve`, `remove`, `bytes`. |
Expand Down
4 changes: 3 additions & 1 deletion crates/fmt/src/state/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,9 @@ impl<'ast> State<'_, 'ast> {
for (pos, ident) in path.segments().iter().delimited() {
self.print_ident(ident);
if !pos.is_last {
self.zerobreak();
if !self.emit_or_revert {
self.zerobreak();
}
self.word(".");
}
}
Expand Down
42 changes: 28 additions & 14 deletions crates/fmt/src/state/sol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,15 +725,31 @@ impl<'ast> State<'_, 'ast> {
let ast::ItemError { name, parameters } = err;
self.word("error ");
self.print_ident(name);
self.print_parameter_list(parameters, parameters.span, ListFormat::compact());
self.print_parameter_list(
parameters,
parameters.span,
if self.config.prefer_compact.errors() {
ListFormat::compact()
} else {
ListFormat::consistent()
},
);
self.word(";");
}

fn print_event(&mut self, event: &'ast ast::ItemEvent<'ast>) {
let ast::ItemEvent { name, parameters, anonymous } = event;
self.word("event ");
self.print_ident(name);
self.print_parameter_list(parameters, parameters.span, ListFormat::compact().break_cmnts());
self.print_parameter_list(
parameters,
parameters.span,
if self.config.prefer_compact.events() {
ListFormat::compact().break_cmnts()
} else {
ListFormat::consistent().break_cmnts()
},
);
if *anonymous {
self.word(" anonymous");
}
Expand Down Expand Up @@ -1701,7 +1717,7 @@ impl<'ast> State<'_, 'ast> {
}

fn print_named_args(&mut self, args: &'ast [ast::NamedArg<'ast>], pos_hi: BytePos) {
let list_format = match (self.config.bracket_spacing, self.config.call_compact_args) {
let list_format = match (self.config.bracket_spacing, self.config.prefer_compact.calls()) {
(false, true) => ListFormat::compact(),
(false, false) => ListFormat::consistent(),
(true, true) => ListFormat::compact().with_space(),
Expand Down Expand Up @@ -1738,7 +1754,7 @@ impl<'ast> State<'_, 'ast> {
.break_cmnts()
.break_single(true)
.without_ind(self.call_stack.is_chain())
.with_delimiters(!(self.emit_or_revert || self.call_with_opts_and_args)),
.with_delimiters(!self.call_with_opts_and_args),
);
} else if self.config.bracket_spacing {
self.nbsp();
Expand Down Expand Up @@ -2264,17 +2280,14 @@ impl<'ast> State<'_, 'ast> {
self.nbsp();
};
self.s.cbox(0);
self.print_path(path, false);
self.emit_or_revert = path.segments().len() > 1;
self.print_call_args(
args,
if self.config.call_compact_args {
ListFormat::compact().break_cmnts().with_delimiters(args.len() == 1)
} else {
ListFormat::consistent().break_cmnts().with_delimiters(args.len() == 1)
},
path.to_string().len(),
);
self.print_path(path, false);
let format = if self.config.prefer_compact.calls() {
ListFormat::compact()
} else {
ListFormat::consistent()
};
self.print_call_args(args, format.break_cmnts(), path.to_string().len());
self.emit_or_revert = false;
self.end();
}
Expand Down Expand Up @@ -2797,6 +2810,7 @@ fn has_complex_successor(expr_kind: &ast::ExprKind<'_>, left: bool) -> bool {
}
ast::ExprKind::Unary(_, expr) => has_complex_successor(&expr.kind, left),
ast::ExprKind::Lit(..) | ast::ExprKind::Ident(_) => false,
ast::ExprKind::Tuple(..) => false,
_ => true,
}
}
Expand Down
4 changes: 1 addition & 3 deletions crates/fmt/testdata/DocComments/wrap-comments.fmt.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// config: line_length = 40
// config: wrap_comments = true
// config: call_compact_args = false
pragma solidity ^0.8.13;

/// @title A Hello world example
Expand All @@ -24,8 +23,7 @@ contract HelloWorld {
/// @param age The dude's age
constructor(uint256 age) {
theDude = Person({
age: age,
wallet: msg.sender
age: age, wallet: msg.sender
});
}

Expand Down
48 changes: 48 additions & 0 deletions crates/fmt/testdata/EmitStatement/120.compact.fmt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// config: line_length = 120
event NewEvent(address beneficiary, uint256 index, uint64 timestamp, uint64 endTimestamp);

function emitEvent() {
emit NewEvent(beneficiary, _vestingBeneficiaries.length - 1, uint64(block.timestamp), endTimestamp);

emit NewEvent( /* beneficiary */
beneficiary,
/* index */
_vestingBeneficiaries.length - 1,
/* timestamp */
uint64(block.timestamp),
/* end timestamp */
endTimestamp
);

emit NewEvent(
beneficiary, // beneficiary
_vestingBeneficiaries.length - 1, // index
uint64(block.timestamp), // timestamp
endTimestamp // end timestamp
);

// https://github.com/foundry-rs/foundry/issues/12029
emit OperatorSharesDecreased(
defaultOperator,
address(0),
strategyMock,
depositAmount / 6 // 1 withdrawal not queued so decreased
);

// https://github.com/foundry-rs/foundry/issues/12146
emit ISablierComptroller.DisableCustomFeeUSD(
protocol_protocol, caller_caller, user_users.sender, previousMinFeeUSD_0, newMinFeeUSD_feeUSD
);
emit ISablierComptroller.DisableCustomFeeUSD({
protocol: protocol, caller: caller, user: users.sender, previousMinFeeUSD: 0, newMinFeeUSD: feeUSD
});

emit ISablierLockupLinear.CreateLockupLinearStream({
streamId: streamId,
commonParams: Lockup.CreateEventCommon({
funder: msg.sender, sender: sender, recipient: recipient, depositAmount: depositAmount
}),
cliffTime: cliffTime,
unlockAmounts: unlockAmounts
});
}
22 changes: 14 additions & 8 deletions crates/fmt/testdata/EmitStatement/120.fmt.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// config: line_length = 120
// config: prefer_compact = "none"
event NewEvent(address beneficiary, uint256 index, uint64 timestamp, uint64 endTimestamp);

function emitEvent() {
Expand Down Expand Up @@ -30,9 +31,19 @@ function emitEvent() {
);

// https://github.com/foundry-rs/foundry/issues/12146
emit ISablierComptroller.DisableCustomFeeUSD(protocol, caller, users.sender, 0, feeUSD);
emit ISablierComptroller.DisableCustomFeeUSD(
protocol_protocol,
caller_caller,
user_users.sender,
previousMinFeeUSD_0,
newMinFeeUSD_feeUSD
);
emit ISablierComptroller.DisableCustomFeeUSD({
protocol: protocol, caller: caller, user: users.sender, previousMinFeeUSD: 0, newMinFeeUSD: feeUSD
protocol: protocol,
caller: caller,
user: users.sender,
previousMinFeeUSD: 0,
newMinFeeUSD: feeUSD
});

emit ISablierLockupLinear.CreateLockupLinearStream({
Expand All @@ -41,12 +52,7 @@ function emitEvent() {
funder: msg.sender,
sender: sender,
recipient: recipient,
depositAmount: depositAmount,
token: token,
cancelable: cancelable,
transferable: transferable,
timestamps: timestamps,
shape: shape
depositAmount: depositAmount
}),
cliffTime: cliffTime,
unlockAmounts: unlockAmounts
Expand Down
13 changes: 6 additions & 7 deletions crates/fmt/testdata/EmitStatement/fmt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ function emitEvent() {

// https://github.com/foundry-rs/foundry/issues/12146
emit ISablierComptroller.DisableCustomFeeUSD(
protocol, caller, users.sender, 0, feeUSD
protocol_protocol,
caller_caller,
user_users.sender,
previousMinFeeUSD_0,
newMinFeeUSD_feeUSD
);
emit ISablierComptroller.DisableCustomFeeUSD({
protocol: protocol,
Expand All @@ -54,12 +58,7 @@ function emitEvent() {
funder: msg.sender,
sender: sender,
recipient: recipient,
depositAmount: depositAmount,
token: token,
cancelable: cancelable,
transferable: transferable,
timestamps: timestamps,
shape: shape
depositAmount: depositAmount
}),
cliffTime: cliffTime,
unlockAmounts: unlockAmounts
Expand Down
9 changes: 2 additions & 7 deletions crates/fmt/testdata/EmitStatement/original.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function emitEvent() {
);

// https://github.com/foundry-rs/foundry/issues/12146
emit ISablierComptroller.DisableCustomFeeUSD(protocol, caller, users.sender, 0, feeUSD);
emit ISablierComptroller.DisableCustomFeeUSD(protocol_protocol, caller_caller, user_users.sender, previousMinFeeUSD_0, newMinFeeUSD_feeUSD);
emit ISablierComptroller.DisableCustomFeeUSD({ protocol: protocol, caller: caller, user: users.sender, previousMinFeeUSD: 0, newMinFeeUSD: feeUSD });

emit ISablierLockupLinear.CreateLockupLinearStream({
Expand All @@ -40,12 +40,7 @@ function emitEvent() {
funder: msg.sender,
sender: sender,
recipient: recipient,
depositAmount: depositAmount,
token: token,
cancelable: cancelable,
transferable: transferable,
timestamps: timestamps,
shape: shape
depositAmount: depositAmount
}),
cliffTime: cliffTime,
unlockAmounts: unlockAmounts
Expand Down
2 changes: 1 addition & 1 deletion crates/fmt/testdata/NamedFunctionCallExpression/fmt.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// config: call_compact_args = false
// config: prefer_compact = "events_errors"
contract NamedFunctionCallExpression {
struct SimpleStruct {
uint256 val;
Expand Down
3 changes: 3 additions & 0 deletions crates/fmt/testdata/OperatorExpressions/120.fmt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,8 @@ contract Repro {
|| chainId == LINEA || chainId == MODE || chainId == MORPH || chainId == OPTIMISM || chainId == POLYGON
|| chainId == SCROLL || chainId == SEI || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC
|| chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC;

callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32))
+ FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288);
}
}
3 changes: 3 additions & 0 deletions crates/fmt/testdata/OperatorExpressions/fmt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,8 @@ contract Repro {
|| chainId == POLYGON || chainId == SCROLL || chainId == SEI
|| chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC
|| chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC;

callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32))
+ FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288);
}
}
2 changes: 2 additions & 0 deletions crates/fmt/testdata/OperatorExpressions/original.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,7 @@ contract Repro {
|| chainId == MODE || chainId == MORPH || chainId == OPTIMISM || chainId == POLYGON || chainId == SCROLL
|| chainId == SEI || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC || chainId == UNICHAIN
|| chainId == XDC || chainId == ZKSYNC;

callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32)) + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,8 @@ contract Repro {
|| chainId == POLYGON || chainId == SCROLL || chainId == SEI
|| chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC
|| chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC;

callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32))
+ FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// config: call_compact_args = false
// config: prefer_compact = "events_errors"
// config: bracket_spacing = true
contract RevertNamedArgsStatement {
error EmptyError();
Expand Down
2 changes: 1 addition & 1 deletion crates/fmt/testdata/RevertNamedArgsStatement/fmt.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// config: call_compact_args = false
// config: prefer_compact = "events_errors"
contract RevertNamedArgsStatement {
error EmptyError();
error SimpleError(uint256 val);
Expand Down
9 changes: 7 additions & 2 deletions crates/fmt/testdata/RevertStatement/fmt.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// config: prefer_compact = "none"
contract RevertStatement {
error TestError(uint256, bool, string);

Expand Down Expand Up @@ -42,11 +43,15 @@ contract RevertStatement {

revert TestError(0, false, message);
revert TestError(
0, false, someVeryLongFunctionNameToGetDynamicErrorMessageString()
0,
false,
someVeryLongFunctionNameToGetDynamicErrorMessageString()
);

revert /* comment13 */ /* comment14 */ TestError( /* comment15 */
1234567890, false, message
1234567890,
false,
message
);

revert TestError( /* comment16 */
Expand Down
Loading
Loading