Skip to content

Commit bacf5b0

Browse files
mattsseRPate97
authored andcommitted
fix: dont strip empty () on constructors (foundry-rs#6740)
* fix: dont strip empty () on constructors * else if
1 parent 25392c0 commit bacf5b0

File tree

4 files changed

+62
-0
lines changed

4 files changed

+62
-0
lines changed

crates/fmt/src/formatter.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ struct Context {
8080
if_stmt_single_line: Option<bool>,
8181
}
8282

83+
impl Context {
84+
/// Returns true if the current function context is the constructor
85+
pub(crate) fn is_constructor_function(&self) -> bool {
86+
self.function.as_ref().map_or(false, |f| matches!(f.ty, FunctionTy::Constructor))
87+
}
88+
}
89+
8390
/// A Solidity formatter
8491
#[derive(Debug)]
8592
pub struct Formatter<'a, W> {
@@ -3047,6 +3054,18 @@ impl<'a, W: Write> Visitor for Formatter<'a, W> {
30473054
self.visit_list("", args, None, Some(loc.end()), false)?
30483055
}
30493056
FunctionAttribute::BaseOrModifier(loc, base) => {
3057+
// here we need to find out if this attribute belongs to the constructor because the
3058+
// modifier need to include the trailing parenthesis
3059+
// This is very ambiguous because the modifier can either by an inherited contract
3060+
// or a modifier here: e.g.: This is valid constructor:
3061+
// `constructor() public Ownable() OnlyOwner {}`
3062+
let is_constructor = self.context.is_constructor_function();
3063+
// we can't make any decisions here regarding trailing `()` because we'd need to
3064+
// find out if the `base` is a solidity modifier or an
3065+
// interface/contract therefor we we its raw content.
3066+
3067+
// we can however check if the contract `is` the `base`, this however also does
3068+
// not cover all cases
30503069
let is_contract_base = self.context.contract.as_ref().map_or(false, |contract| {
30513070
contract.base.iter().any(|contract_base| {
30523071
contract_base
@@ -3060,6 +3079,20 @@ impl<'a, W: Write> Visitor for Formatter<'a, W> {
30603079

30613080
if is_contract_base {
30623081
base.visit(self)?;
3082+
} else if is_constructor {
3083+
// This is ambiguous because the modifier can either by an inherited
3084+
// contract modifiers with empty parenthesis are
3085+
// valid, but not required so we make the assumption
3086+
// here that modifiers are lowercase
3087+
let mut base_or_modifier =
3088+
self.visit_to_chunk(loc.start(), Some(loc.end()), base)?;
3089+
let is_lowercase =
3090+
base_or_modifier.content.chars().next().map_or(false, |c| c.is_lowercase());
3091+
if is_lowercase && base_or_modifier.content.ends_with("()") {
3092+
base_or_modifier.content.truncate(base_or_modifier.content.len() - 2);
3093+
}
3094+
3095+
self.write_chunk(&base_or_modifier)?;
30633096
} else {
30643097
let mut base_or_modifier =
30653098
self.visit_to_chunk(loc.start(), Some(loc.end()), base)?;
@@ -3110,6 +3143,8 @@ impl<'a, W: Write> Visitor for Formatter<'a, W> {
31103143
})?;
31113144

31123145
if base.args.is_none() || base.args.as_ref().unwrap().is_empty() {
3146+
// This is ambiguous because the modifier can either by an inherited contract or a
3147+
// modifier
31133148
if self.context.function.is_some() {
31143149
name.content.push_str("()");
31153150
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.5.2;
4+
5+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
6+
import {ERC1155} from "solmate/tokens/ERC1155.sol";
7+
8+
import {IAchievements} from "./interfaces/IAchievements.sol";
9+
import {SoulBound1155} from "./abstracts/SoulBound1155.sol";
10+
11+
contract Achievements is IAchievements, SoulBound1155, Ownable {
12+
constructor(address owner) Ownable() ERC1155() {}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.5.2;
4+
5+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
6+
import {ERC1155} from "solmate/tokens/ERC1155.sol";
7+
8+
import {IAchievements} from "./interfaces/IAchievements.sol";
9+
import {SoulBound1155} from "./abstracts/SoulBound1155.sol";
10+
11+
contract Achievements is IAchievements, SoulBound1155, Ownable {
12+
constructor(address owner) Ownable() ERC1155() {}
13+
}

crates/fmt/tests/formatter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ macro_rules! test_directories {
181181

182182
test_directories! {
183183
ConstructorDefinition,
184+
ConstructorModifierStyle,
184185
ContractDefinition,
185186
DocComments,
186187
EnumDefinition,

0 commit comments

Comments
 (0)