From b8fdb666e235bb6b19f11dba7740227026111598 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 4 Apr 2018 12:28:22 +0200 Subject: Allow duplicated constructor calls, if no arguments; support for multiple inheritance; backwards compatibility. # tmp --- Changelog.md | 2 +- libsolidity/analysis/StaticAnalyzer.cpp | 50 +++++++++++++--------- ...low_empty_duplicated_super_constructor_call.sol | 3 ++ .../base_arguments_multiple_inheritance.sol | 9 ++++ .../duplicated_ancestor_constructor_call.sol | 5 +++ .../duplicated_ancestor_constructor_call_V050.sol | 7 +++ .../duplicated_super_constructor_call.sol | 2 +- .../duplicated_super_constructor_call_V050.sol | 6 +++ .../duplicated_super_constructor_call_empty.sol | 4 -- .../duplicated_super_constructor_call_multi.sol | 7 +++ 10 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 test/libsolidity/syntaxTests/inheritance/allow_empty_duplicated_super_constructor_call.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/base_arguments_multiple_inheritance.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/duplicated_ancestor_constructor_call.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/duplicated_ancestor_constructor_call_V050.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_V050.sol delete mode 100644 test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_empty.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_multi.sol diff --git a/Changelog.md b/Changelog.md index 94703f7d..3b8cba1d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,7 @@ Features: * Optimizer: Remove useless ``SWAP1`` instruction preceding a commutative instruction (such as ``ADD``, ``MUL``, etc). * Optimizer: Replace comparison operators (``LT``, ``GT``, etc) with opposites if preceded by ``SWAP1``, e.g. ``SWAP1 LT`` is replaced with ``GT``. * Optimizer: Optimize across ``mload`` if ``msize()`` is not used. + * Static Analyzer: Error on duplicated super constructor calls as experimental 0.5.0 feature. * Syntax Checker: Issue warning for empty structs (or error as experimental 0.5.0 feature). * General: Introduce new constructor syntax using the ``constructor`` keyword as experimental 0.5.0 feature. * Inheritance: Error when using empty parenthesis for base class constructors that require arguments as experimental 0.5.0 feature. @@ -28,7 +29,6 @@ Bugfixes: * Type System: Make external library functions accessible. * Type System: Prevent encoding of weird types. * Static Analyzer: Fix non-deterministic order of unused variable warnings. - * Static Analyzer: Error on duplicated super constructor calls. ### 0.4.21 (2018-03-07) diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index 6c70ba6b..700c8a71 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -90,33 +90,43 @@ void StaticAnalyzer::endVisit(FunctionDefinition const&) m_localVarUseCount.clear(); } -bool modifierOverridesInheritanceSpecifier( - ContractDefinition const* _contract, - ModifierInvocation const& _modifier, - InheritanceSpecifier const& _specifier -) -{ - auto parent = _specifier.name().annotation().referencedDeclaration; - return _contract == parent && (!_specifier.arguments().empty() || _modifier.arguments().empty()); -} - bool StaticAnalyzer::visit(ModifierInvocation const& _modifier) { if (!m_constructor) return true; + bool const v050 = m_currentContract->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); + if (auto contract = dynamic_cast(_modifier.name()->annotation().referencedDeclaration)) - for (auto const& specifier: m_currentContract->baseContracts()) - if (modifierOverridesInheritanceSpecifier(contract, _modifier, *specifier)) + for (auto const& base: m_currentContract->annotation().linearizedBaseContracts) + for (auto const& specifier: base->baseContracts()) { - SecondarySourceLocation ssl; - ssl.append("Overriden constructor call is here:", specifier->location()); - - m_errorReporter.declarationError( - _modifier.location(), - ssl, - "Duplicated super constructor call." - ); + Declaration const* parent = specifier->name().annotation().referencedDeclaration; + if (contract == parent && !specifier->arguments().empty()) + { + if (v050) + { + SecondarySourceLocation ssl; + ssl.append("Second constructor call is here:", specifier->location()); + + m_errorReporter.declarationError( + _modifier.location(), + ssl, + "Duplicated super constructor call." + ); + } + else + { + SecondarySourceLocation ssl; + ssl.append("Overridden constructor call is here:", specifier->location()); + + m_errorReporter.warning( + _modifier.location(), + "Duplicated super constructor calls are deprecated.", + ssl + ); + } + } } return true; diff --git a/test/libsolidity/syntaxTests/inheritance/allow_empty_duplicated_super_constructor_call.sol b/test/libsolidity/syntaxTests/inheritance/allow_empty_duplicated_super_constructor_call.sol new file mode 100644 index 00000000..1f580b1d --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/allow_empty_duplicated_super_constructor_call.sol @@ -0,0 +1,3 @@ +contract A { constructor() public { } } +contract B1 is A { constructor() A() public { } } +contract B2 is A { constructor() A public { } } diff --git a/test/libsolidity/syntaxTests/inheritance/base_arguments_multiple_inheritance.sol b/test/libsolidity/syntaxTests/inheritance/base_arguments_multiple_inheritance.sol new file mode 100644 index 00000000..f63d0f02 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/base_arguments_multiple_inheritance.sol @@ -0,0 +1,9 @@ +contract Base { + constructor(uint) public { } +} +contract Base1 is Base(3) {} +contract Derived is Base, Base1 { + constructor(uint i) Base(i) public {} +} +// ---- +// Warning: Duplicated super constructor calls are deprecated. diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_ancestor_constructor_call.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_ancestor_constructor_call.sol new file mode 100644 index 00000000..97f3f8ff --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/duplicated_ancestor_constructor_call.sol @@ -0,0 +1,5 @@ +contract A { constructor(uint) public { } } +contract B is A(2) { constructor() public { } } +contract C is B { constructor() A(3) public { } } +// ---- +// Warning: Duplicated super constructor calls are deprecated. diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_ancestor_constructor_call_V050.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_ancestor_constructor_call_V050.sol new file mode 100644 index 00000000..933c9087 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/duplicated_ancestor_constructor_call_V050.sol @@ -0,0 +1,7 @@ +pragma experimental "v0.5.0"; + +contract A { constructor(uint) public { } } +contract B is A(2) { constructor() public { } } +contract C is B { constructor() A(3) public { } } +// ---- +// DeclarationError: Duplicated super constructor call. diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call.sol index 95df1040..876b07ea 100644 --- a/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call.sol +++ b/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call.sol @@ -1,4 +1,4 @@ contract A { constructor(uint) public { } } contract B is A(2) { constructor() A(3) public { } } // ---- -// DeclarationError: Duplicated super constructor call. +// Warning: Duplicated super constructor calls are deprecated. diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_V050.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_V050.sol new file mode 100644 index 00000000..31a363fd --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_V050.sol @@ -0,0 +1,6 @@ +pragma experimental "v0.5.0"; + +contract A { constructor(uint) public { } } +contract B is A(2) { constructor() A(3) public { } } +// ---- +// DeclarationError: Duplicated super constructor call. diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_empty.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_empty.sol deleted file mode 100644 index f8024ad6..00000000 --- a/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_empty.sol +++ /dev/null @@ -1,4 +0,0 @@ -contract A { constructor() public { } } -contract B is A { constructor() A() public { } } -// ---- -// DeclarationError: Duplicated super constructor call. diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_multi.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_multi.sol new file mode 100644 index 00000000..caed18eb --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/duplicated_super_constructor_call_multi.sol @@ -0,0 +1,7 @@ +contract C { constructor(uint) public {} } +contract A is C(2) {} +contract B is C(2) {} +contract D is A, B { constructor() C(3) public {} } +// ---- +// Warning: Duplicated super constructor calls are deprecated. +// Warning: Duplicated super constructor calls are deprecated. -- cgit