From 6c6a9054b2e60d6011b35a282e26f0d38792a9dd Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Mon, 16 Sep 2019 14:33:43 +0200 Subject: [PATCH] Implement override checking --- Changelog.md | 1 + docs/contracts/abstract-contracts.rst | 2 +- docs/contracts/inheritance.rst | 140 +++++- docs/structure-of-a-contract.rst | 5 + docs/style-guide.rst | 4 +- libdevcore/CommonData.h | 53 ++- libsolidity/analysis/ContractLevelChecker.cpp | 409 ++++++++++++++++-- libsolidity/analysis/ContractLevelChecker.h | 37 +- libsolidity/ast/ASTAnnotations.h | 2 +- .../MultiSigWalletWithDailyLimit.sol | 1 + test/compilationTests/corion/premium.sol | 2 +- test/compilationTests/corion/provider.sol | 6 +- test/compilationTests/corion/publisher.sol | 2 +- test/compilationTests/corion/schelling.sol | 4 +- test/compilationTests/corion/token.sol | 2 +- .../gnosis/Events/CategoricalEvent.sol | 2 + .../gnosis/Events/ScalarEvent.sol | 2 + .../gnosis/MarketMakers/LMSRMarketMaker.sol | 3 + .../gnosis/Markets/StandardMarket.sol | 7 + .../gnosis/Markets/StandardMarketFactory.sol | 1 + .../gnosis/Oracles/CentralizedOracle.sol | 2 + .../gnosis/Oracles/DifficultyOracle.sol | 2 + .../gnosis/Oracles/FutarchyOracle.sol | 2 + .../gnosis/Oracles/MajorityOracle.sol | 2 + .../gnosis/Oracles/SignedMessageOracle.sol | 2 + .../gnosis/Oracles/UltimateOracle.sol | 2 + .../gnosis/Tokens/StandardToken.sol | 6 + test/contracts/AuctionRegistrar.cpp | 16 +- test/contracts/FixedFeeRegistrar.cpp | 8 +- test/contracts/Wallet.cpp | 13 +- test/externalTests/solc-js/DAO/DAO.sol | 45 +- .../solc-js/DAO/ManagedAccount.sol | 2 +- test/externalTests/solc-js/DAO/Token.sol | 10 +- .../solc-js/DAO/TokenCreation.sol | 7 +- test/libsolidity/Metadata.cpp | 4 +- test/libsolidity/SolidityEndToEndTest.cpp | 44 +- .../SolidityNameAndTypeResolution.cpp | 2 +- test/libsolidity/SolidityTypes.cpp | 2 +- .../functionCall/base_base_overload.sol | 4 +- .../viaYul/virtual_functions.sol | 2 +- .../inheritance/override/add_view.sol | 1 + .../inheritance/override/calldata_memory.sol | 8 +- .../override/calldata_memory_conflict.sol | 28 +- .../override/calldata_memory_interface.sol | 8 +- .../calldata_memory_interface_instantiate.sol | 4 +- .../calldata_memory_interface_struct.sol | 8 +- .../override/calldata_memory_struct.sol | 8 +- .../change_return_types_in_interface.sol | 1 + .../external_turns_public_no_params.sol | 2 +- .../override/internal_external.sol | 1 - .../internal_external_inheritance.sol | 2 +- .../inheritance/override/override.sol | 8 +- .../override/override_ambiguous.sol | 14 + .../override/override_base_base.sol | 20 + .../override/override_multiple.sol | 16 +- .../override/override_multiple2.sol | 15 + .../override/override_multiple_duplicated.sol | 26 ++ .../override/override_multiple_missing.sol | 24 + .../override/override_multiple_unresolved.sol | 6 + .../override/override_return_mismatch.sol | 14 + .../override/override_shared_base.sol | 15 + .../override/override_shared_base_partial.sol | 10 + .../override/override_shared_base_simple.sol | 6 + .../inheritance/override/remove_view.sol | 1 + .../inheritance/super_on_external.sol | 4 +- .../modifiers/illegal_modifier_override.sol | 1 + .../modifiers/modifier_overrides_function.sol | 2 +- ...lemented_abstract_function_as_abstract.sol | 5 +- .../055_inheritance_diamond_basic.sol | 3 +- .../059_illegal_override_visibility.sol | 1 + .../060_complex_inheritance.sol | 2 +- .../079_fallback_function_inheritance.sol | 2 +- ..._override_function_with_bytearray_type.sol | 2 +- .../181_override_changes_return_types.sol | 4 +- .../182_equal_overload.sol | 1 - .../358_illegal_override_payable.sol | 1 + ...59_illegal_override_payable_nonpayable.sol | 1 + .../423_using_interface.sol | 2 +- .../424_using_interface_complex.sol | 2 +- ...25_interface_implement_public_contract.sol | 2 +- .../unimplemented_super_function.sol | 4 +- .../unimplemented_super_function_derived.sol | 6 +- .../syntaxTests/viewPureChecker/interface.sol | 2 +- .../viewPureChecker/overriding_fail.sol | 12 +- .../overriding_no_restrict_warning.sol | 2 +- 85 files changed, 965 insertions(+), 204 deletions(-) create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_ambiguous.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_base_base.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_multiple2.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_multiple_duplicated.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_multiple_missing.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_multiple_unresolved.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_return_mismatch.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_shared_base.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_shared_base_partial.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_shared_base_simple.sol diff --git a/Changelog.md b/Changelog.md index 9bbe29f35..d35af58ca 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,6 +12,7 @@ Breaking changes: * Syntax: ``push(element)`` for dynamic storage arrays do not return the new length anymore. * Inline Assembly: Only strict inline assembly is allowed. * Type checker: Resulting type of exponentiation is equal to the type of the base. Also allow signed types for the base. + * Language Feature: When overriding a function or modifier, the new keyword ``override`` must be used. When overriding a function or modifier defined in multiple parallel bases, all bases must be listed in parentheses after the keyword like so: ``override(Base1, Base2)`` Language Features: * Allow global enums and structs. diff --git a/docs/contracts/abstract-contracts.rst b/docs/contracts/abstract-contracts.rst index 924805467..5eb111a51 100644 --- a/docs/contracts/abstract-contracts.rst +++ b/docs/contracts/abstract-contracts.rst @@ -23,7 +23,7 @@ Such contracts cannot be compiled (even if they contain implemented functions al } contract Cat is Feline { - function utterance() public returns (bytes32) { return "miaow"; } + function utterance() public override returns (bytes32) { return "miaow"; } } If a contract inherits from an abstract contract and does not implement all non-implemented functions by overriding, it will itself be abstract. diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index 28df381ee..3f72af96f 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -10,6 +10,9 @@ All function calls are virtual, which means that the most derived function is called, except when the contract name is explicitly given or the ``super`` keyword is used. +All functions overriding a base function must specify the ``override`` keyword. +See :ref:`Function Overriding ` for more details. + When a contract inherits from other contracts, only a single contract is created on the blockchain, and the code from all the base contracts is compiled into the created contract. This means that all internal calls @@ -74,7 +77,7 @@ Details are given in the following example. // types of output parameters, that causes an error. // Both local and message-based function calls take these overrides // into account. - function kill() public { + function kill() public override { if (msg.sender == owner) { Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970); NameReg(config.lookup(1)).unregister(); @@ -94,6 +97,7 @@ Details are given in the following example. if (msg.sender == owner) info = newInfo; } + function kill() public override (Mortal, Named) { Named.kill(); } function get() public view returns(uint r) { return info; } uint info; @@ -117,20 +121,20 @@ seen in the following example:: } contract Base1 is mortal { - function kill() public { /* do cleanup 1 */ mortal.kill(); } + function kill() public override { /* do cleanup 1 */ mortal.kill(); } } contract Base2 is mortal { - function kill() public { /* do cleanup 2 */ mortal.kill(); } + function kill() public override { /* do cleanup 2 */ mortal.kill(); } } contract Final is Base1, Base2 { + function kill() public override(Base1, Base2) { Base2.kill(); } } -A call to ``Final.kill()`` will call ``Base2.kill`` as the most -derived override, but this function will bypass -``Base1.kill``, basically because it does not even know about -``Base1``. The way around this is to use ``super``:: +A call to ``Final.kill()`` will call ``Base2.kill`` because we specify it +explicitly in the final override, but this function will bypass +``Base1.kill``. The way around this is to use ``super``:: pragma solidity >=0.4.22 <0.7.0; @@ -146,15 +150,16 @@ derived override, but this function will bypass } contract Base1 is mortal { - function kill() public { /* do cleanup 1 */ super.kill(); } + function kill() public override { /* do cleanup 1 */ super.kill(); } } contract Base2 is mortal { - function kill() public { /* do cleanup 2 */ super.kill(); } + function kill() public override { /* do cleanup 2 */ super.kill(); } } contract Final is Base1, Base2 { + function kill() public override(Base1, Base2) { super.kill(); } } If ``Base2`` calls a function of ``super``, it does not simply @@ -168,6 +173,123 @@ not known in the context of the class where it is used, although its type is known. This is similar for ordinary virtual method lookup. +.. _function-overriding: + +.. index:: ! overriding;function + +Function Overriding +=================== + +Base functions can be overridden by inheriting contracts to change their +behavior. The overriding function must then use the ``override`` keyword in the +function header as shown in this example: + +:: + + pragma solidity >=0.5.0 <0.7.0; + + contract Base + { + function foo() public {} + } + + contract Middle is Base {} + + contract Inherited is Middle + { + function foo() public override {} + } + +For multiple inheritance, the most derived base contracts that define the same +function must be specified explicitly after the ``override`` keyword. +In other words, you have to specify all base contracts that define the same function and have not yet been overridden by another base contract (on some path through the inheritance graph). +Additionally, if a contract inherits the same function from multiple (unrelated) +bases, it has to explicitly override it: + +:: + + pragma solidity >=0.5.0 <0.7.0; + + contract Base1 + { + function foo() public {} + } + + contract Base2 + { + function foo() public {} + } + + contract Inherited is Base1, Base2 + { + // Derives from multiple bases defining foo(), so we must explicitly + // override it + function foo() public override(Base1, Base2) {} + } + +A function defined in a common base contract does not have to be explicitly +overridden when used with multiple inheritance: + +:: + + pragma solidity >=0.5.0 <0.7.0; + + contract A { function f() public pure{} } + contract B is A {} + contract C is A {} + // No explicit override required + contract D is B, C {} + +.. _modifier-overriding: + +.. index:: ! overriding;modifier + +Modifier Overriding +=================== + +Function modifiers can override each other. This works in the same way as +function overriding (except that there is no overloading for modifiers). The +``override`` keyword must be used in the overriding contract: + +:: + + pragma solidity >=0.5.0 <0.7.0; + + contract Base + { + modifier foo() {_;} + } + + contract Inherited is Base + { + modifier foo() override {_;} + } + + +In case of multiple inheritance, all direct base contracts must be specified +explicitly: + +:: + + pragma solidity >=0.5.0 <0.7.0; + + contract Base1 + { + modifier foo() {_;} + } + + contract Base2 + { + modifier foo() {_;} + } + + contract Inherited is Base1, Base2 + { + modifier foo() override(Base1, Base2) {_;} + } + + + .. index:: ! constructor .. _constructor: diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index 01ed23233..b6d70c5a3 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -67,6 +67,11 @@ Function Modifiers Function modifiers can be used to amend the semantics of functions in a declarative way (see :ref:`modifiers` in the contracts section). +Overloading, that is, having the same modifier name with different parameters, +is not possible. + +Like functions, modifiers can be :ref:`overridden `. + :: pragma solidity >=0.4.22 <0.7.0; diff --git a/docs/style-guide.rst b/docs/style-guide.rst index aa2c1c305..736d47ac9 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -98,11 +98,11 @@ Yes:: contract B is A { - function spam() public pure { + function spam() public override pure { // ... } - function ham() public pure { + function ham() public override pure { // ... } } diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 017a632dc..274365649 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -23,6 +23,7 @@ #pragma once +#include #include #include @@ -49,14 +50,27 @@ template std::vector& operator+=(std::vector& _a, U&& _ std::move(_b.begin(), _b.end(), std::back_inserter(_a)); return _a; } +/// Concatenate the contents of a container onto a multiset +template std::multiset& operator+=(std::multiset& _a, U const& _b) +{ + _a.insert(_b.begin(), _b.end()); + return _a; +} +/// Concatenate the contents of a container onto a multiset, move variant. +template std::multiset& operator+=(std::multiset& _a, U&& _b) +{ + for (auto&& x: _b) + _a.insert(std::move(x)); + return _a; +} /// Concatenate the contents of a container onto a set -template std::set& operator+=(std::set& _a, U const& _b) +template std::set& operator+=(std::set& _a, U const& _b) { _a.insert(_b.begin(), _b.end()); return _a; } /// Concatenate the contents of a container onto a set, move variant. -template std::set& operator+=(std::set& _a, U&& _b) +template std::set& operator+=(std::set& _a, U&& _b) { for (auto&& x: _b) _a.insert(std::move(x)); @@ -97,18 +111,43 @@ inline std::set operator+(std::set&& _a, U&& _b) ret += std::forward(_b); return ret; } + /// Remove one set from another one. -template -inline std::set& operator-=(std::set& _a, std::set const& _b) +template +inline std::set& operator-=(std::set& _a, std::set const& _b) { for (auto const& x: _b) _a.erase(x); return _a; } +template +inline std::set operator-(std::set const& _a, std::set const& _b) +{ + auto result = _a; + result -= _b; + + return result; +} + namespace dev { +template +T convertContainer(U const& _from) +{ + return T{_from.cbegin(), _from.cend()}; +} + +template +T convertContainer(U&& _from) +{ + return T{ + std::make_move_iterator(_from.begin()), + std::make_move_iterator(_from.end()) + }; +} + // String conversion functions, mainly to/from hex/nibble/byte representations. enum class WhenError @@ -262,6 +301,12 @@ bool contains(T const& _t, V const& _v) return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v); } +template +bool contains_if(T const& _t, Predicate const& _p) +{ + return std::end(_t) != std::find_if(std::begin(_t), std::end(_t), _p); +} + /// Function that iterates over a vector, calling a function on each of its /// elements. If that function returns a vector, the element is replaced by /// the returned vector. During the iteration, the original vector is only valid diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index b291fb98e..89b8db63c 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace std; @@ -33,17 +34,95 @@ using namespace dev; using namespace langutil; using namespace dev::solidity; -namespace { +namespace +{ + +// Helper struct to do a search by name +struct MatchByName +{ + string const& m_name; + bool operator()(CallableDeclaration const* _callable) + { + return _callable->name() == m_name; + } +}; + +vector> sortByContract(vector> const& _list) +{ + auto sorted = _list; + + sort(sorted.begin(), sorted.end(), + [] (ASTPointer _a, ASTPointer _b) { + if (!_a || !_b) + return _a < _b; + + Declaration const* aDecl = _a->annotation().referencedDeclaration; + Declaration const* bDecl = _b->annotation().referencedDeclaration; + + if (!aDecl || !bDecl) + return aDecl < bDecl; + + return aDecl->id() < bDecl->id(); + } + ); + + return sorted; +} template bool hasEqualNameAndParameters(T const& _a, T const& _b) { - return _a.name() == _b.name() && + return + _a.name() == _b.name() && FunctionType(_a).asCallableFunction(false)->hasEqualParameterTypes( *FunctionType(_b).asCallableFunction(false) ); } +vector resolveDirectBaseContracts(ContractDefinition const& _contract) +{ + vector resolvedContracts; + + for (ASTPointer const& specifier: _contract.baseContracts()) + { + Declaration const* baseDecl = + specifier->name().annotation().referencedDeclaration; + auto contract = dynamic_cast(baseDecl); + solAssert(contract, "contract is null"); + resolvedContracts.emplace_back(contract); + } + + return resolvedContracts; +} + +} + +bool ContractLevelChecker::LessFunction::operator()(ModifierDefinition const* _a, ModifierDefinition const* _b) const +{ + return _a->name() < _b->name(); +} + +bool ContractLevelChecker::LessFunction::operator()(FunctionDefinition const* _a, FunctionDefinition const* _b) const +{ + if (_a->name() != _b->name()) + return _a->name() < _b->name(); + + return boost::lexicographical_compare( + FunctionType(*_a).asCallableFunction(false)->parameterTypes(), + FunctionType(*_b).asCallableFunction(false)->parameterTypes(), + [](auto const& _paramTypeA, auto const& _paramTypeB) + { + return _paramTypeA->richIdentifier() < _paramTypeB->richIdentifier(); + } + ); +} + +bool ContractLevelChecker::LessFunction::operator()(ContractDefinition const* _a, ContractDefinition const* _b) const +{ + if (!_a || !_b) + return _a < _b; + + return _a->id() < _b->id(); } bool ContractLevelChecker::check(ContractDefinition const& _contract) @@ -51,6 +130,7 @@ bool ContractLevelChecker::check(ContractDefinition const& _contract) checkDuplicateFunctions(_contract); checkDuplicateEvents(_contract); checkIllegalOverrides(_contract); + checkAmbiguousOverrides(_contract); checkAbstractFunctions(_contract); checkBaseConstructorArguments(_contract); checkConstructor(_contract); @@ -145,50 +225,52 @@ void ContractLevelChecker::findDuplicateDefinitions(map> const void ContractLevelChecker::checkIllegalOverrides(ContractDefinition const& _contract) { - // TODO unify this at a later point. for this we need to put the constness and the access specifier - // into the types - map> functions; - map modifiers; + FunctionMultiSet const& funcSet = inheritedFunctions(&_contract); + ModifierMultiSet const& modSet = inheritedModifiers(&_contract); - // We search from derived to base, so the stored item causes the error. - for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) + checkModifierOverrides(funcSet, modSet, _contract.functionModifiers()); + + for (FunctionDefinition const* function: _contract.definedFunctions()) { - for (FunctionDefinition const* function: contract->definedFunctions()) - { - if (function->isConstructor()) - continue; // constructors can neither be overridden nor override anything - string const& name = function->name(); - if (modifiers.count(name)) - m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier."); + if (contains_if(modSet, MatchByName{function->name()})) + m_errorReporter.typeError(function->location(), "Override changes modifier to function."); - for (FunctionDefinition const* overriding: functions[name]) - checkFunctionOverride(*overriding, *function); + // Skip if not overridable + if (!function->isOverridable()) + continue; - functions[name].push_back(function); - } - for (ModifierDefinition const* modifier: contract->functionModifiers()) - { - string const& name = modifier->name(); - ModifierDefinition const*& override = modifiers[name]; - if (!override) - override = modifier; - else if (ModifierType(*override) != ModifierType(*modifier)) - m_errorReporter.typeError(override->location(), "Override changes modifier signature."); - if (!functions[name].empty()) - m_errorReporter.typeError(override->location(), "Override changes modifier to function."); - } + // No inheriting functions found + if (funcSet.find(function) == funcSet.cend() && function->overrides()) + m_errorReporter.typeError( + function->overrides()->location(), + "Function has override specified but does not override anything." + ); + + checkOverrideList(funcSet, *function); } } -void ContractLevelChecker::checkFunctionOverride(FunctionDefinition const& _function, FunctionDefinition const& _super) +bool ContractLevelChecker::checkFunctionOverride(FunctionDefinition const& _function, FunctionDefinition const& _super) { FunctionTypePointer functionType = FunctionType(_function).asCallableFunction(false); FunctionTypePointer superType = FunctionType(_super).asCallableFunction(false); + bool success = true; + if (!functionType->hasEqualParameterTypes(*superType)) - return; + return true; + + if (!_function.overrides()) + { + overrideError(_function, _super, "Overriding function is missing 'override' specifier."); + success = false; + } + if (!functionType->hasEqualReturnTypes(*superType)) + { overrideError(_function, _super, "Overriding function return types differ."); + success = false; + } if (!_function.annotation().superFunction) _function.annotation().superFunction = &_super; @@ -201,9 +283,13 @@ void ContractLevelChecker::checkFunctionOverride(FunctionDefinition const& _func _super.visibility() == FunctionDefinition::Visibility::External && _function.visibility() == FunctionDefinition::Visibility::Public )) + { overrideError(_function, _super, "Overriding function visibility differs."); + success = false; + } } if (_function.stateMutability() != _super.stateMutability()) + { overrideError( _function, _super, @@ -213,9 +299,38 @@ void ContractLevelChecker::checkFunctionOverride(FunctionDefinition const& _func stateMutabilityToString(_function.stateMutability()) + "\"." ); + success = false; + } + + return success; } -void ContractLevelChecker::overrideError(FunctionDefinition const& function, FunctionDefinition const& super, string message) +void ContractLevelChecker::overrideListError(FunctionDefinition const& function, set _secondary, string const& _message1, string const& _message2) +{ + // Using a set rather than a vector so the order is always the same + set names; + SecondarySourceLocation ssl; + for (Declaration const* c: _secondary) + { + ssl.append("This contract: ", c->location()); + names.insert(c->name()); + } + string contractSingularPlural = "contract "; + if (_secondary.size() > 1) + contractSingularPlural = "contracts "; + + m_errorReporter.typeError( + function.overrides() ? function.overrides()->location() : function.location(), + ssl, + _message1 + + contractSingularPlural + + _message2 + + joinHumanReadable(names, ", ", " and ") + + "." + ); +} + +void ContractLevelChecker::overrideError(CallableDeclaration const& function, CallableDeclaration const& super, string message) { m_errorReporter.typeError( function.location(), @@ -520,3 +635,231 @@ void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _ ); } + +void ContractLevelChecker::checkAmbiguousOverrides(ContractDefinition const& _contract) const +{ + vector contractFuncs = _contract.definedFunctions(); + + auto const resolvedBases = resolveDirectBaseContracts(_contract); + + FunctionMultiSet inheritedFuncs = inheritedFunctions(&_contract);; + + // Check the sets of the most-inherited functions + for (auto it = inheritedFuncs.cbegin(); it != inheritedFuncs.cend(); it = inheritedFuncs.upper_bound(*it)) + { + auto [begin,end] = inheritedFuncs.equal_range(*it); + + // Only one function + if (next(begin) == end) + continue; + + // Not an overridable function + if (!(*it)->isOverridable()) + { + for (begin++; begin != end; begin++) + solAssert(!(*begin)->isOverridable(), "All functions in range expected to be non-overridable!"); + continue; + } + + // Function has been explicitly overridden + if (contains_if( + contractFuncs, + [&] (FunctionDefinition const* _f) { + return hasEqualNameAndParameters(*_f, **it); + } + )) + continue; + + set ambiguousFunctions; + SecondarySourceLocation ssl; + + for (;begin != end; begin++) + { + ambiguousFunctions.insert(*begin); + ssl.append("Definition here: ", (*begin)->location()); + } + + // Make sure the functions are not from the same base contract + if (ambiguousFunctions.size() == 1) + continue; + + m_errorReporter.typeError( + _contract.location(), + ssl, + "Derived contract must override function \"" + + (*it)->name() + + "\". Function with the same name and parameter types defined in two or more base classes." + ); + } +} + +set ContractLevelChecker::resolveOverrideList(OverrideSpecifier const& _overrides) const +{ + set resolved; + + for (ASTPointer const& override: _overrides.overrides()) + { + Declaration const* decl = override->annotation().referencedDeclaration; + solAssert(decl, "Expected declaration to be resolved."); + + // If it's not a contract it will be caught + // in the reference resolver + if (ContractDefinition const* contract = dynamic_cast(decl)) + resolved.insert(contract); + } + + return resolved; +} + + +void ContractLevelChecker::checkModifierOverrides(FunctionMultiSet const& _funcSet, ModifierMultiSet const& _modSet, std::vector _modifiers) +{ + for (ModifierDefinition const* modifier: _modifiers) + { + if (contains_if(_funcSet, MatchByName{modifier->name()})) + m_errorReporter.typeError( + modifier->location(), + "Override changes function to modifier." + ); + + auto [begin,end] = _modSet.equal_range(modifier); + + // Skip if no modifiers found in bases + if (begin == end) + continue; + + if (!modifier->overrides()) + overrideError(*modifier, **begin, "Overriding modifier is missing 'override' specifier."); + + for (; begin != end; begin++) + if (ModifierType(**begin) != ModifierType(*modifier)) + m_errorReporter.typeError( + modifier->location(), + "Override changes modifier signature." + ); + } + +} + +void ContractLevelChecker::checkOverrideList(FunctionMultiSet const& _funcSet, FunctionDefinition const& _function) +{ + set specifiedContracts = + _function.overrides() ? + resolveOverrideList(*_function.overrides()) : + decltype(specifiedContracts){}; + + // Check for duplicates in override list + if (_function.overrides() && specifiedContracts.size() != _function.overrides()->overrides().size()) + { + // Sort by contract id to find duplicate for error reporting + vector> list = + sortByContract(_function.overrides()->overrides()); + + // Find duplicates and output error + for (size_t i = 1; i < list.size(); i++) + { + Declaration const* aDecl = list[i]->annotation().referencedDeclaration; + Declaration const* bDecl = list[i-1]->annotation().referencedDeclaration; + if (!aDecl || !bDecl) + continue; + + if (aDecl->id() == bDecl->id()) + { + SecondarySourceLocation ssl; + ssl.append("First occurrence here: ", list[i-1]->location()); + m_errorReporter.typeError( + list[i]->location(), + ssl, + "Duplicate contract \"" + + joinHumanReadable(list[i]->namePath(), ".") + + "\" found in override list of \"" + + _function.name() + + "\"." + ); + } + } + } + + decltype(specifiedContracts) expectedContracts; + + // Build list of expected contracts + for (auto [begin, end] = _funcSet.equal_range(&_function); begin != end; begin++) + { + // Validate the override + if (!checkFunctionOverride(_function, **begin)) + break; + + expectedContracts.insert((*begin)->annotation().contract); + } + + decltype(specifiedContracts) missingContracts; + decltype(specifiedContracts) surplusContracts; + + // If we expect only one contract, no contract needs to be specified + if (expectedContracts.size() > 1) + missingContracts = expectedContracts - specifiedContracts; + + surplusContracts = specifiedContracts - expectedContracts; + + if (!missingContracts.empty()) + overrideListError( + _function, + missingContracts, + "Function needs to specify overridden ", + "" + ); + + if (!surplusContracts.empty()) + overrideListError( + _function, + surplusContracts, + "Invalid ", + "specified in override list: " + ); +} + +ContractLevelChecker::FunctionMultiSet const& ContractLevelChecker::inheritedFunctions(ContractDefinition const* _contract) const +{ + if (!m_inheritedFunctions.count(_contract)) + { + FunctionMultiSet set; + + for (auto const* base: resolveDirectBaseContracts(*_contract)) + { + std::set tmpSet = + convertContainer(base->definedFunctions()); + + for (auto const& func: inheritedFunctions(base)) + tmpSet.insert(func); + + set += tmpSet; + } + + m_inheritedFunctions[_contract] = set; + } + + return m_inheritedFunctions[_contract]; +} + +ContractLevelChecker::ModifierMultiSet const& ContractLevelChecker::inheritedModifiers(ContractDefinition const* _contract) const +{ + auto const& result = m_contractBaseModifiers.find(_contract); + + if (result != m_contractBaseModifiers.cend()) + return result->second; + + ModifierMultiSet set; + + for (auto const* base: resolveDirectBaseContracts(*_contract)) + { + std::set tmpSet = + convertContainer(base->functionModifiers()); + + for (auto const& mod: inheritedModifiers(base)) + tmpSet.insert(mod); + + set += tmpSet; + } + + return m_contractBaseModifiers[_contract] = set; +} diff --git a/libsolidity/analysis/ContractLevelChecker.h b/libsolidity/analysis/ContractLevelChecker.h index f2cd9887f..9c74edf38 100644 --- a/libsolidity/analysis/ContractLevelChecker.h +++ b/libsolidity/analysis/ContractLevelChecker.h @@ -23,6 +23,7 @@ #include #include +#include namespace langutil { @@ -41,6 +42,7 @@ namespace solidity class ContractLevelChecker { public: + /// @param _errorReporter provides the error logging functionality. explicit ContractLevelChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) @@ -51,6 +53,16 @@ public: bool check(ContractDefinition const& _contract); private: + struct LessFunction + { + bool operator()(ModifierDefinition const* _a, ModifierDefinition const* _b) const; + bool operator()(FunctionDefinition const* _a, FunctionDefinition const* _b) const; + bool operator()(ContractDefinition const* _a, ContractDefinition const* _b) const; + }; + + using FunctionMultiSet = std::multiset; + using ModifierMultiSet = std::multiset; + /// Checks that two functions defined in this contract with the same name have different /// arguments and that there is at most one constructor. void checkDuplicateFunctions(ContractDefinition const& _contract); @@ -58,10 +70,12 @@ private: template void findDuplicateDefinitions(std::map> const& _definitions, std::string _message); void checkIllegalOverrides(ContractDefinition const& _contract); - /// Reports a type error with an appropriate message if overridden function signature differs. + /// Returns false and reports a type error with an appropriate + /// message if overridden function signature differs. /// Also stores the direct super function in the AST annotations. - void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super); - void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message); + bool checkFunctionOverride(FunctionDefinition const& _function, FunctionDefinition const& _super); + void overrideListError(FunctionDefinition const& function, std::set _secondary, std::string const& _message1, std::string const& _message2); + void overrideError(CallableDeclaration const& function, CallableDeclaration const& super, std::string message); void checkAbstractFunctions(ContractDefinition const& _contract); void checkBaseConstructorArguments(ContractDefinition const& _contract); void annotateBaseConstructorArguments( @@ -80,8 +94,25 @@ private: void checkLibraryRequirements(ContractDefinition const& _contract); /// Checks base contracts for ABI compatibility void checkBaseABICompatibility(ContractDefinition const& _contract); + /// Checks for functions in different base contracts which conflict with each + /// other and thus need to be overridden explicitly. + void checkAmbiguousOverrides(ContractDefinition const& _contract) const; + /// Resolves an override list of UserDefinedTypeNames to a list of contracts. + std::set resolveOverrideList(OverrideSpecifier const& _overrides) const; + + void checkModifierOverrides(FunctionMultiSet const& _funcSet, ModifierMultiSet const& _modSet, std::vector _modifiers); + void checkOverrideList(FunctionMultiSet const& _funcSet, FunctionDefinition const& _function); + + /// Returns all functions of bases that have not yet been overwritten. + /// May contain the same function multiple times when used with shared bases. + FunctionMultiSet const& inheritedFunctions(ContractDefinition const* _contract) const; + ModifierMultiSet const& inheritedModifiers(ContractDefinition const* _contract) const; langutil::ErrorReporter& m_errorReporter; + + /// Cache for inheritedFunctions(). + std::map mutable m_inheritedFunctions; + std::map mutable m_contractBaseModifiers; }; } diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index d1f70c828..fb3df1341 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -109,7 +109,7 @@ struct FunctionDefinitionAnnotation: ASTAnnotation, DocumentedAnnotation /// The function this function overrides, if any. This is always the closest /// in the linearized inheritance hierarchy. FunctionDefinition const* superFunction = nullptr; - /// Reference to the contract this function is defined in + /// Pointer to the contract this function is defined in ContractDefinition const* contract = nullptr; }; diff --git a/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol b/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol index fc0a3bc5a..65116d9f0 100644 --- a/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol +++ b/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol @@ -40,6 +40,7 @@ contract MultiSigWalletWithDailyLimit is MultiSigWallet { /// @param transactionId Transaction ID. function executeTransaction(uint transactionId) public + override notExecuted(transactionId) { Transaction storage tx = transactions[transactionId]; diff --git a/test/compilationTests/corion/premium.sol b/test/compilationTests/corion/premium.sol index 091e291ac..66f3282a2 100644 --- a/test/compilationTests/corion/premium.sol +++ b/test/compilationTests/corion/premium.sol @@ -12,7 +12,7 @@ contract thirdPartyPContractAbstract { contract ptokenDB is tokenDB {} contract premium is module, safeMath { - function replaceModule(address payable addr) external returns (bool success) { + function replaceModule(address payable addr) external override returns (bool success) { require( super.isModuleHandler(msg.sender) ); require( db.replaceOwner(addr) ); super._replaceModule(addr); diff --git a/test/compilationTests/corion/provider.sol b/test/compilationTests/corion/provider.sol index 0789c7b5d..0b9f4ac1c 100644 --- a/test/compilationTests/corion/provider.sol +++ b/test/compilationTests/corion/provider.sol @@ -9,14 +9,14 @@ contract provider is module, safeMath, announcementTypes { /* module callbacks */ - function connectModule() external returns (bool success) { + function connectModule() external override returns (bool success) { require( super.isModuleHandler(msg.sender) ); super._connectModule(); (bool _success, uint256 currentSchellingRound) = moduleHandler(moduleHandlerAddress).getCurrentSchellingRoundID(); require( _success ); return true; } - function transferEvent(address payable from, address payable to, uint256 value) external returns (bool success) { + function transferEvent(address payable from, address payable to, uint256 value) external override returns (bool success) { /* Transaction completed. This function is only available for the modulehandler. It should be checked if the sender or the acceptor does not connect to the provider or it is not a provider itself if so than the change should be recorded. @@ -31,7 +31,7 @@ contract provider is module, safeMath, announcementTypes { transferEvent_(to, value, false); return true; } - function newSchellingRoundEvent(uint256 roundID, uint256 reward) external returns (bool success) { + function newSchellingRoundEvent(uint256 roundID, uint256 reward) external override returns (bool success) { /* New schelling round. This function is only available for the moduleHandler. We are recording the new schelling round and we are storing the whole current quantity of the tokens. diff --git a/test/compilationTests/corion/publisher.sol b/test/compilationTests/corion/publisher.sol index 991fc8f48..19746ec57 100644 --- a/test/compilationTests/corion/publisher.sol +++ b/test/compilationTests/corion/publisher.sol @@ -9,7 +9,7 @@ contract publisher is announcementTypes, module, safeMath { /* module callbacks */ - function transferEvent(address payable from, address payable to, uint256 value) external returns (bool success) { + function transferEvent(address payable from, address payable to, uint256 value) external override returns (bool success) { /* Transaction completed. This function is available only for moduleHandler If a transaction is carried out from or to an address which participated in the objection of an announcement, its objection purport is automatically set diff --git a/test/compilationTests/corion/schelling.sol b/test/compilationTests/corion/schelling.sol index 9ab24133a..b70d6797f 100644 --- a/test/compilationTests/corion/schelling.sol +++ b/test/compilationTests/corion/schelling.sol @@ -134,13 +134,13 @@ contract schelling is module, announcementTypes, schellingVars { /* module callbacks */ - function replaceModule(address payable addr) external returns (bool) { + function replaceModule(address payable addr) external override returns (bool) { require( super.isModuleHandler(msg.sender) ); require( db.replaceOwner(addr) ); super._replaceModule(addr); return true; } - function transferEvent(address payable from, address payable to, uint256 value) external returns (bool) { + function transferEvent(address payable from, address payable to, uint256 value) external override returns (bool) { /* Transaction completed. This function can be called only by the ModuleHandler. If this contract is the receiver, the amount will be added to the prize pool of the current round. diff --git a/test/compilationTests/corion/token.sol b/test/compilationTests/corion/token.sol index 6ab225302..b966d6833 100644 --- a/test/compilationTests/corion/token.sol +++ b/test/compilationTests/corion/token.sol @@ -15,7 +15,7 @@ contract token is safeMath, module, announcementTypes { /* module callbacks */ - function replaceModule(address payable addr) external returns (bool success) { + function replaceModule(address payable addr) external override returns (bool success) { require( super.isModuleHandler(msg.sender) ); require( db.replaceOwner(addr) ); super._replaceModule(addr); diff --git a/test/compilationTests/gnosis/Events/CategoricalEvent.sol b/test/compilationTests/gnosis/Events/CategoricalEvent.sol index 0d6d1b459..4f564166f 100644 --- a/test/compilationTests/gnosis/Events/CategoricalEvent.sol +++ b/test/compilationTests/gnosis/Events/CategoricalEvent.sol @@ -28,6 +28,7 @@ contract CategoricalEvent is Event { /// @return Sender's winnings function redeemWinnings() public + override returns (uint winnings) { // Winning outcome has to be set @@ -45,6 +46,7 @@ contract CategoricalEvent is Event { /// @return Event hash function getEventHash() public + override view returns (bytes32) { diff --git a/test/compilationTests/gnosis/Events/ScalarEvent.sol b/test/compilationTests/gnosis/Events/ScalarEvent.sol index 325f43023..ad9bc3ad6 100644 --- a/test/compilationTests/gnosis/Events/ScalarEvent.sol +++ b/test/compilationTests/gnosis/Events/ScalarEvent.sol @@ -47,6 +47,7 @@ contract ScalarEvent is Event { /// @return Sender's winnings function redeemWinnings() public + override returns (uint winnings) { // Winning outcome has to be set @@ -79,6 +80,7 @@ contract ScalarEvent is Event { /// @return Event hash function getEventHash() public + override view returns (bytes32) { diff --git a/test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol b/test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol index c305d168c..deea3fc44 100644 --- a/test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol +++ b/test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol @@ -24,6 +24,7 @@ contract LMSRMarketMaker is MarketMaker { /// @return Cost function calcCost(Market market, uint8 outcomeTokenIndex, uint outcomeTokenCount) public + override view returns (uint cost) { @@ -59,6 +60,7 @@ contract LMSRMarketMaker is MarketMaker { /// @return Profit function calcProfit(Market market, uint8 outcomeTokenIndex, uint outcomeTokenCount) public + override view returns (uint profit) { @@ -85,6 +87,7 @@ contract LMSRMarketMaker is MarketMaker { /// @return Marginal price of an outcome as a fixed point number function calcMarginalPrice(Market market, uint8 outcomeTokenIndex) public + override view returns (uint price) { diff --git a/test/compilationTests/gnosis/Markets/StandardMarket.sol b/test/compilationTests/gnosis/Markets/StandardMarket.sol index 99648c903..9437202e6 100644 --- a/test/compilationTests/gnosis/Markets/StandardMarket.sol +++ b/test/compilationTests/gnosis/Markets/StandardMarket.sol @@ -56,6 +56,7 @@ contract StandardMarket is Market { /// @param _funding Funding amount function fund(uint _funding) public + override isCreator atStage(Stages.MarketCreated) { @@ -70,6 +71,7 @@ contract StandardMarket is Market { /// @dev Allows market creator to close the markets by transferring all remaining outcome tokens to the creator function close() + override public isCreator atStage(Stages.MarketFunded) @@ -85,6 +87,7 @@ contract StandardMarket is Market { /// @return Fee amount function withdrawFees() public + override isCreator returns (uint fees) { @@ -101,6 +104,7 @@ contract StandardMarket is Market { /// @return Cost in collateral tokens function buy(uint8 outcomeTokenIndex, uint outcomeTokenCount, uint maxCost) public + override atStage(Stages.MarketFunded) returns (uint cost) { @@ -131,6 +135,7 @@ contract StandardMarket is Market { /// @return Profit in collateral tokens function sell(uint8 outcomeTokenIndex, uint outcomeTokenCount, uint minProfit) public + override atStage(Stages.MarketFunded) returns (uint profit) { @@ -161,6 +166,7 @@ contract StandardMarket is Market { /// @return Cost to short sell outcome in collateral tokens function shortSell(uint8 outcomeTokenIndex, uint outcomeTokenCount, uint minProfit) public + override returns (uint cost) { // Buy all outcomes @@ -186,6 +192,7 @@ contract StandardMarket is Market { /// @return Fee for trade function calcMarketFee(uint outcomeTokenCost) public + override view returns (uint) { diff --git a/test/compilationTests/gnosis/Markets/StandardMarketFactory.sol b/test/compilationTests/gnosis/Markets/StandardMarketFactory.sol index 7245da890..a542a2573 100644 --- a/test/compilationTests/gnosis/Markets/StandardMarketFactory.sol +++ b/test/compilationTests/gnosis/Markets/StandardMarketFactory.sol @@ -17,6 +17,7 @@ contract StandardMarketFactory is MarketFactory { /// @return Market contract function createMarket(Event eventContract, MarketMaker marketMaker, uint24 fee) public + override returns (Market market) { market = new StandardMarket(msg.sender, eventContract, marketMaker, fee); diff --git a/test/compilationTests/gnosis/Oracles/CentralizedOracle.sol b/test/compilationTests/gnosis/Oracles/CentralizedOracle.sol index ee0d50a34..97253229c 100644 --- a/test/compilationTests/gnosis/Oracles/CentralizedOracle.sol +++ b/test/compilationTests/gnosis/Oracles/CentralizedOracle.sol @@ -72,6 +72,7 @@ contract CentralizedOracle is Oracle { /// @return Is outcome set? function isOutcomeSet() public + override view returns (bool) { @@ -82,6 +83,7 @@ contract CentralizedOracle is Oracle { /// @return Outcome function getOutcome() public + override view returns (int) { diff --git a/test/compilationTests/gnosis/Oracles/DifficultyOracle.sol b/test/compilationTests/gnosis/Oracles/DifficultyOracle.sol index c1b432351..a42f2ba66 100644 --- a/test/compilationTests/gnosis/Oracles/DifficultyOracle.sol +++ b/test/compilationTests/gnosis/Oracles/DifficultyOracle.sol @@ -44,6 +44,7 @@ contract DifficultyOracle is Oracle { /// @return Is outcome set? function isOutcomeSet() public + override view returns (bool) { @@ -55,6 +56,7 @@ contract DifficultyOracle is Oracle { /// @return Outcome function getOutcome() public + override view returns (int) { diff --git a/test/compilationTests/gnosis/Oracles/FutarchyOracle.sol b/test/compilationTests/gnosis/Oracles/FutarchyOracle.sol index ad56dcdc2..84675ba96 100644 --- a/test/compilationTests/gnosis/Oracles/FutarchyOracle.sol +++ b/test/compilationTests/gnosis/Oracles/FutarchyOracle.sol @@ -151,6 +151,7 @@ contract FutarchyOracle is Oracle { /// @return Is outcome set? function isOutcomeSet() public + override view returns (bool) { @@ -161,6 +162,7 @@ contract FutarchyOracle is Oracle { /// @return Outcome function getOutcome() public + override view returns (int) { diff --git a/test/compilationTests/gnosis/Oracles/MajorityOracle.sol b/test/compilationTests/gnosis/Oracles/MajorityOracle.sol index 6913713b1..c10ff8a42 100644 --- a/test/compilationTests/gnosis/Oracles/MajorityOracle.sol +++ b/test/compilationTests/gnosis/Oracles/MajorityOracle.sol @@ -70,6 +70,7 @@ contract MajorityOracle is Oracle { /// @return Is outcome set? function isOutcomeSet() public + override view returns (bool) { @@ -81,6 +82,7 @@ contract MajorityOracle is Oracle { /// @return Outcome function getOutcome() public + override view returns (int) { diff --git a/test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol b/test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol index 900067cd0..694b73742 100644 --- a/test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol +++ b/test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol @@ -84,6 +84,7 @@ contract SignedMessageOracle is Oracle { /// @return Is outcome set? function isOutcomeSet() public + override view returns (bool) { @@ -94,6 +95,7 @@ contract SignedMessageOracle is Oracle { /// @return Outcome function getOutcome() public + override view returns (int) { diff --git a/test/compilationTests/gnosis/Oracles/UltimateOracle.sol b/test/compilationTests/gnosis/Oracles/UltimateOracle.sol index d45747150..4bbd6673d 100644 --- a/test/compilationTests/gnosis/Oracles/UltimateOracle.sol +++ b/test/compilationTests/gnosis/Oracles/UltimateOracle.sol @@ -174,6 +174,7 @@ contract UltimateOracle is Oracle { /// @return Is outcome set? function isOutcomeSet() public + override view returns (bool) { @@ -185,6 +186,7 @@ contract UltimateOracle is Oracle { /// @return Outcome function getOutcome() public + override view returns (int) { diff --git a/test/compilationTests/gnosis/Tokens/StandardToken.sol b/test/compilationTests/gnosis/Tokens/StandardToken.sol index 09916cc1f..b7073115a 100644 --- a/test/compilationTests/gnosis/Tokens/StandardToken.sol +++ b/test/compilationTests/gnosis/Tokens/StandardToken.sol @@ -23,6 +23,7 @@ contract StandardToken is Token { /// @return Was transfer successful? function transfer(address to, uint value) public + override returns (bool) { if ( !balances[msg.sender].safeToSub(value) @@ -41,6 +42,7 @@ contract StandardToken is Token { /// @return Was transfer successful? function transferFrom(address from, address to, uint value) public + override returns (bool) { if ( !balances[from].safeToSub(value) @@ -60,6 +62,7 @@ contract StandardToken is Token { /// @return Was approval successful? function approve(address spender, uint value) public + override returns (bool) { allowances[msg.sender][spender] = value; @@ -73,6 +76,7 @@ contract StandardToken is Token { /// @return Remaining allowance for spender function allowance(address owner, address spender) public + override view returns (uint) { @@ -84,6 +88,7 @@ contract StandardToken is Token { /// @return Balance of owner function balanceOf(address owner) public + override view returns (uint) { @@ -94,6 +99,7 @@ contract StandardToken is Token { /// @return Total supply function totalSupply() public + override view returns (uint) { diff --git a/test/contracts/AuctionRegistrar.cpp b/test/contracts/AuctionRegistrar.cpp index 7e0f6e58c..c91e4c25c 100644 --- a/test/contracts/AuctionRegistrar.cpp +++ b/test/contracts/AuctionRegistrar.cpp @@ -55,11 +55,11 @@ contract Registrar is NameRegister { event PrimaryChanged(string indexed name, address indexed addr); function owner(string memory _name) public view returns (address o_owner); - function addr(string memory _name) public view returns (address o_address); + function addr(string memory _name) public override view returns (address o_address); function subRegistrar(string memory _name) public view returns (address o_subRegistrar); function content(string memory _name) public view returns (bytes32 o_content); - function name(address _owner) public view returns (string memory o_name); + function name(address _owner) public override view returns (string memory o_name); } contract AuctionSystem { @@ -119,7 +119,7 @@ contract GlobalRegistrar is Registrar, AuctionSystem { // TODO: Populate with hall-of-fame. } - function onAuctionEnd(string memory _name) internal { + function onAuctionEnd(string memory _name) internal override { Auction storage auction = m_auctions[_name]; Record storage record = m_toRecord[_name]; address previousOwner = record.owner; @@ -204,11 +204,11 @@ contract GlobalRegistrar is Registrar, AuctionSystem { return true; } - function owner(string memory _name) public view returns (address) { return m_toRecord[_name].owner; } - function addr(string memory _name) public view returns (address) { return m_toRecord[_name].primary; } - function subRegistrar(string memory _name) public view returns (address) { return m_toRecord[_name].subRegistrar; } - function content(string memory _name) public view returns (bytes32) { return m_toRecord[_name].content; } - function name(address _addr) public view returns (string memory o_name) { return m_toName[_addr]; } + function owner(string memory _name) public override view returns (address) { return m_toRecord[_name].owner; } + function addr(string memory _name) public override view returns (address) { return m_toRecord[_name].primary; } + function subRegistrar(string memory _name) public override view returns (address) { return m_toRecord[_name].subRegistrar; } + function content(string memory _name) public override view returns (bytes32) { return m_toRecord[_name].content; } + function name(address _addr) public override view returns (string memory o_name) { return m_toName[_addr]; } mapping (address => string) m_toName; mapping (string => Record) m_toRecord; diff --git a/test/contracts/FixedFeeRegistrar.cpp b/test/contracts/FixedFeeRegistrar.cpp index 4d8be54f0..51bc5aae2 100644 --- a/test/contracts/FixedFeeRegistrar.cpp +++ b/test/contracts/FixedFeeRegistrar.cpp @@ -111,10 +111,10 @@ contract FixedFeeRegistrar is Registrar { o_content = rec.content; o_owner = rec.owner; } - function addr(string memory _name) public view returns (address) { return m_record(_name).addr; } - function subRegistrar(string memory _name) public view returns (address) { return m_record(_name).subRegistrar; } - function content(string memory _name) public view returns (bytes32) { return m_record(_name).content; } - function owner(string memory _name) public view returns (address) { return m_record(_name).owner; } + function addr(string memory _name) public override view returns (address) { return m_record(_name).addr; } + function subRegistrar(string memory _name) public override view returns (address) { return m_record(_name).subRegistrar; } + function content(string memory _name) public override view returns (bytes32) { return m_record(_name).content; } + function owner(string memory _name) public override view returns (address) { return m_record(_name).owner; } Record[2**253] m_recordData; function m_record(string memory _name) view internal returns (Record storage o_record) { diff --git a/test/contracts/Wallet.cpp b/test/contracts/Wallet.cpp index ed981f565..e25ac0cda 100644 --- a/test/contracts/Wallet.cpp +++ b/test/contracts/Wallet.cpp @@ -128,7 +128,7 @@ contract multiowned { } // Replaces an owner `_from` with another `_to`. - function changeOwner(address _from, address _to) onlymanyowners(keccak256(msg.data)) external { + function changeOwner(address _from, address _to) onlymanyowners(keccak256(msg.data)) public { if (isOwner(_to)) return; uint ownerIndex = m_ownerIndex[uint(_from)]; if (ownerIndex == 0) return; @@ -347,7 +347,7 @@ contract multisig { // FUNCTIONS // TODO: document - function changeOwner(address _from, address _to) external; + function changeOwner(address _from, address _to) public; function execute(address _to, uint _value, bytes calldata _data) external returns (bytes32); function confirm(bytes32 _h) public returns (bool); } @@ -374,6 +374,9 @@ contract Wallet is multisig, multiowned, daylimit { multiowned(_owners, _required) daylimit(_daylimit) { } + function changeOwner(address _from, address _to) public override(multiowned, multisig) { + multiowned.changeOwner(_from, _to); + } // destroys the contract sending everything to `_to`. function kill(address payable _to) onlymanyowners(keccak256(msg.data)) external { selfdestruct(_to); @@ -390,7 +393,7 @@ contract Wallet is multisig, multiowned, daylimit { // If not, goes into multisig process. We provide a hash on return to allow the sender to provide // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value // and _data arguments). They still get the option of using them if they want, anyways. - function execute(address _to, uint _value, bytes calldata _data) external onlyowner returns (bytes32 _r) { + function execute(address _to, uint _value, bytes calldata _data) external override onlyowner returns (bytes32 _r) { // first, take the opportunity to check that we're under the daily limit. if (underLimit(_value)) { emit SingleTransact(msg.sender, _value, _to, _data); @@ -410,7 +413,7 @@ contract Wallet is multisig, multiowned, daylimit { // confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order // to determine the body of the transaction from the hash provided. - function confirm(bytes32 _h) onlymanyowners(_h) public returns (bool) { + function confirm(bytes32 _h) onlymanyowners(_h) public override returns (bool) { if (m_txs[_h].to != 0x0000000000000000000000000000000000000000) { m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data); emit MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data); @@ -421,7 +424,7 @@ contract Wallet is multisig, multiowned, daylimit { // INTERNAL METHODS - function clearPending() internal { + function clearPending() internal override { uint length = m_pendingIndex.length; for (uint i = 0; i < length; ++i) delete m_txs[m_pendingIndex[i]]; diff --git a/test/externalTests/solc-js/DAO/DAO.sol b/test/externalTests/solc-js/DAO/DAO.sol index d9cefcd0e..7aa95f071 100644 --- a/test/externalTests/solc-js/DAO/DAO.sol +++ b/test/externalTests/solc-js/DAO/DAO.sol @@ -397,7 +397,7 @@ contract DAO is DAOInterface, Token, TokenCreation { } - function receiveEther() public returns (bool) { + function receiveEther() public override returns (bool) { return true; } @@ -409,7 +409,7 @@ contract DAO is DAOInterface, Token, TokenCreation { bytes memory _transactionData, uint _debatingPeriod, bool _newCurator - ) onlyTokenholders public payable returns (uint _proposalID) { + ) onlyTokenholders public override payable returns (uint _proposalID) { // Sanity check if (_newCurator && ( @@ -479,7 +479,7 @@ contract DAO is DAOInterface, Token, TokenCreation { address payable _recipient, uint _amount, bytes memory _transactionData - ) public view returns (bool _codeChecksOut) { + ) public override view returns (bool _codeChecksOut) { Proposal storage p = proposals[_proposalID]; return p.proposalHash == keccak256(abi.encodePacked(_recipient, _amount, _transactionData)); } @@ -488,7 +488,7 @@ contract DAO is DAOInterface, Token, TokenCreation { function vote( uint _proposalID, bool _supportsProposal - ) onlyTokenholders public returns (uint _voteID) { + ) onlyTokenholders public override returns (uint _voteID) { Proposal storage p = proposals[_proposalID]; if (p.votedYes[msg.sender] @@ -521,7 +521,7 @@ contract DAO is DAOInterface, Token, TokenCreation { function executeProposal( uint _proposalID, bytes memory _transactionData - ) public returns (bool _success) { + ) public override returns (bool _success) { Proposal storage p = proposals[_proposalID]; @@ -622,7 +622,7 @@ contract DAO is DAOInterface, Token, TokenCreation { function splitDAO( uint _proposalID, address payable _newCurator - ) onlyTokenholders public returns (bool _success) { + ) onlyTokenholders public override returns (bool _success) { Proposal storage p = proposals[_proposalID]; @@ -694,7 +694,7 @@ contract DAO is DAOInterface, Token, TokenCreation { return true; } - function newContract(address payable _newContract) public { + function newContract(address payable _newContract) public override { if (msg.sender != address(this) || !allowedRecipients[_newContract]) return; // move all ether (bool success,) = _newContract.call.value(address(this).balance)(""); @@ -710,7 +710,7 @@ contract DAO is DAOInterface, Token, TokenCreation { } - function retrieveDAOReward(bool _toMembers) external returns (bool _success) { + function retrieveDAOReward(bool _toMembers) external override returns (bool _success) { DAO dao = DAO(msg.sender); if ((rewardToken[msg.sender] * DAOrewardAccount.accumulatedInput()) / @@ -735,12 +735,13 @@ contract DAO is DAOInterface, Token, TokenCreation { return true; } - function getMyReward() public returns (bool _success) { + function getMyReward() public override returns (bool _success) { return withdrawRewardFor(msg.sender); } - function withdrawRewardFor(address payable _account) noEther internal returns (bool _success) { + function withdrawRewardFor(address payable _account) noEther internal +override returns (bool _success) { if ((balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply < paidOut[_account]) revert(); @@ -756,7 +757,7 @@ contract DAO is DAOInterface, Token, TokenCreation { } - function transfer(address _to, uint256 _value) public returns (bool success) { + function transfer(address _to, uint256 _value) public override returns (bool success) { if (isFueled && now > closingTime && !isBlocked(msg.sender) @@ -771,14 +772,15 @@ contract DAO is DAOInterface, Token, TokenCreation { } - function transferWithoutReward(address _to, uint256 _value) public returns (bool success) { + function transferWithoutReward(address _to, uint256 _value) public override returns (bool success) { if (!getMyReward()) revert(); return transfer(_to, _value); } - function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { + function transferFrom(address _from, address _to, uint256 _value) public +override returns (bool success) { if (isFueled && now > closingTime && !isBlocked(_from) @@ -797,7 +799,7 @@ contract DAO is DAOInterface, Token, TokenCreation { address payable _from, address _to, uint256 _value - ) public returns (bool success) { + ) public override returns (bool success) { if (!withdrawRewardFor(_from)) revert(); @@ -820,7 +822,7 @@ contract DAO is DAOInterface, Token, TokenCreation { } - function changeProposalDeposit(uint _proposalDeposit) external { + function changeProposalDeposit(uint _proposalDeposit) external override { if (msg.sender != address(this) || _proposalDeposit > (actualBalance() + rewardToken[address(this)]) / maxDepositDivisor) { @@ -830,7 +832,8 @@ contract DAO is DAOInterface, Token, TokenCreation { } - function changeAllowedRecipients(address _recipient, bool _allowed) external returns (bool _success) { + function changeAllowedRecipients(address _recipient, bool _allowed) external +override returns (bool _success) { if (msg.sender != curator) revert(); allowedRecipients[_recipient] = _allowed; @@ -862,7 +865,7 @@ contract DAO is DAOInterface, Token, TokenCreation { } - function halveMinQuorum() public returns (bool _success) { + function halveMinQuorum() public override returns (bool _success) { // this can only be called after `quorumHalvingPeriod` has passed or at anytime after // fueling by the curator with a delay of at least `minProposalDebatePeriod` // between the calls @@ -891,16 +894,16 @@ contract DAO is DAOInterface, Token, TokenCreation { ); } - function numberOfProposals() public view returns (uint _numberOfProposals) { + function numberOfProposals() public view override returns (uint _numberOfProposals) { // Don't count index 0. It's used by isBlocked() and exists from start return proposals.length - 1; } - function getNewDAOAddress(uint _proposalID) public view returns (address _newDAO) { + function getNewDAOAddress(uint _proposalID) public override view returns (address _newDAO) { return address(proposals[_proposalID].splitData[0].newDAO); } - function isBlocked(address _account) internal returns (bool) { + function isBlocked(address _account) internal override returns (bool) { if (blocked[_account] == 0) return false; Proposal storage p = proposals[blocked[_account]]; @@ -912,7 +915,7 @@ contract DAO is DAOInterface, Token, TokenCreation { } } - function unblockMe() public returns (bool) { + function unblockMe() public override returns (bool) { return isBlocked(msg.sender); } } diff --git a/test/externalTests/solc-js/DAO/ManagedAccount.sol b/test/externalTests/solc-js/DAO/ManagedAccount.sol index 5edb32696..5ef4b3f2d 100644 --- a/test/externalTests/solc-js/DAO/ManagedAccount.sol +++ b/test/externalTests/solc-js/DAO/ManagedAccount.sol @@ -54,7 +54,7 @@ contract ManagedAccount is ManagedAccountInterface{ accumulatedInput += msg.value; } - function payOut(address payable _recipient, uint _amount) public returns (bool) { + function payOut(address payable _recipient, uint _amount) public override returns (bool) { if (msg.sender != owner || (payOwnerOnly && _recipient != owner)) revert(); (bool success,) = _recipient.call.value(_amount)(""); diff --git a/test/externalTests/solc-js/DAO/Token.sol b/test/externalTests/solc-js/DAO/Token.sol index 77287b9b4..4b490f0dc 100644 --- a/test/externalTests/solc-js/DAO/Token.sol +++ b/test/externalTests/solc-js/DAO/Token.sol @@ -94,11 +94,11 @@ contract Token is TokenInterface { // inadvertently also transferred ether modifier noEther() {if (msg.value > 0) revert(); _; } - function balanceOf(address _owner) public view returns (uint256 balance) { + function balanceOf(address _owner) public override view returns (uint256 balance) { return balances[_owner]; } - function transfer(address _to, uint256 _amount) public returns (bool success) { + function transfer(address _to, uint256 _amount) public override returns (bool success) { if (balances[msg.sender] >= _amount && _amount > 0) { balances[msg.sender] -= _amount; balances[_to] += _amount; @@ -113,7 +113,7 @@ contract Token is TokenInterface { address _from, address _to, uint256 _amount - ) public returns (bool success) { + ) public override returns (bool success) { if (balances[_from] >= _amount && allowed[_from][msg.sender] >= _amount @@ -129,7 +129,7 @@ contract Token is TokenInterface { } } - function approve(address _spender, uint256 _amount) public returns (bool success) { + function approve(address _spender, uint256 _amount) public override returns (bool success) { allowed[msg.sender][_spender] = _amount; emit Approval(msg.sender, _spender, _amount); return true; @@ -144,7 +144,7 @@ contract Token is TokenInterface { return true; } - function allowance(address _owner, address _spender) public view returns (uint256 remaining) { + function allowance(address _owner, address _spender) public override view returns (uint256 remaining) { return allowed[_owner][_spender]; } } diff --git a/test/externalTests/solc-js/DAO/TokenCreation.sol b/test/externalTests/solc-js/DAO/TokenCreation.sol index 1d22ebdf6..ed97106bb 100644 --- a/test/externalTests/solc-js/DAO/TokenCreation.sol +++ b/test/externalTests/solc-js/DAO/TokenCreation.sol @@ -100,7 +100,8 @@ contract TokenCreation is TokenCreationInterface, Token { } - function createTokenProxy(address payable _tokenHolder) payable public returns (bool success) { + function createTokenProxy(address payable _tokenHolder) payable public +override returns (bool success) { if (now < closingTime && msg.value > 0 && (privateCreation == 0x0000000000000000000000000000000000000000 || privateCreation == msg.sender)) { @@ -119,7 +120,7 @@ contract TokenCreation is TokenCreationInterface, Token { revert(); } - function refund() public { + function refund() public override { if (now > closingTime && !isFueled) { // Get extraBalance - will only succeed when called for the first time if (address(extraBalance).balance >= extraBalance.accumulatedInput()) @@ -136,7 +137,7 @@ contract TokenCreation is TokenCreationInterface, Token { } } - function divisor() public view returns (uint divisor) { + function divisor() public override view returns (uint divisor) { // The number of (base unit) tokens per wei is calculated // as `msg.value` * 20 / `divisor` // The fueling period starts with a 1:1 ratio diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index 7f040e1e3..3bd8f662e 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -219,14 +219,14 @@ BOOST_AUTO_TEST_CASE(metadata_relevant_sources_imports) pragma solidity >=0.0; import "./A"; contract B is A { - function g(function(uint) external returns (uint) x) public {} + function g(function(uint) external returns (uint) x) public override {} } )"; char const* sourceCodeC = R"( pragma solidity >=0.0; import "./B"; contract C is B { - function g(function(uint) external returns (uint) x) public {} + function g(function(uint) external returns (uint) x) public override {} } )"; compilerStack.setSources({ diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index dd9ba2d39..0a41d9362 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -2113,7 +2113,7 @@ BOOST_AUTO_TEST_CASE(virtual_function_calls) function g() public returns (uint i) { return 1; } } contract Derived is Base { - function g() public returns (uint i) { return 2; } + function g() public override returns (uint i) { return 2; } } )"; ALSO_VIA_YUL( @@ -2175,10 +2175,10 @@ BOOST_AUTO_TEST_CASE(explicit_base_class) { char const* sourceCode = R"( contract BaseBase { function g() public returns (uint r) { return 1; } } - contract Base is BaseBase { function g() public returns (uint r) { return 2; } } + contract Base is BaseBase { function g() public override returns (uint r) { return 2; } } contract Derived is Base { function f() public returns (uint r) { return BaseBase.g(); } - function g() public returns (uint r) { return 3; } + function g() public override returns (uint r) { return 3; } } )"; compileAndRun(sourceCode, 0, "Derived"); @@ -2243,7 +2243,7 @@ BOOST_AUTO_TEST_CASE(virtual_function_usage_in_constructor_arguments) } contract Derived is Base() { function getA() public returns (uint r) { return m_a; } - function overridden() public returns (uint r) { return 2; } + function overridden() public override returns (uint r) { return 2; } } )"; compileAndRun(sourceCode, 0, "Derived"); @@ -2335,7 +2335,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_overriding) modifier mod { _; } } contract C is A { - modifier mod { if (false) _; } + modifier mod override { if (false) _; } } )"; compileAndRun(sourceCode); @@ -2356,8 +2356,8 @@ BOOST_AUTO_TEST_CASE(function_modifier_calling_functions_in_creation_context) function getData() public returns (uint r) { return data; } } contract C is A { - modifier mod1 { f4(); _; } - function f3() public { data |= 0x300; } + modifier mod1 override { f4(); _; } + function f3() public override { data |= 0x300; } function f4() public { data |= 0x4000; } } )"; @@ -2375,7 +2375,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_for_constructor) function getData() public returns (uint r) { return data; } } contract C is A { - modifier mod1 { data |= 4; _; } + modifier mod1 override { data |= 4; _; } } )"; compileAndRun(sourceCode); @@ -2483,9 +2483,9 @@ BOOST_AUTO_TEST_CASE(super) { char const* sourceCode = R"( contract A { function f() public returns (uint r) { return 1; } } - contract B is A { function f() public returns (uint r) { return super.f() | 2; } } - contract C is A { function f() public returns (uint r) { return super.f() | 4; } } - contract D is B, C { function f() public returns (uint r) { return super.f() | 8; } } + contract B is A { function f() public override returns (uint r) { return super.f() | 2; } } + contract C is A { function f() public override returns (uint r) { return super.f() | 4; } } + contract D is B, C { function f() public override(B, C) returns (uint r) { return super.f() | 8; } } )"; compileAndRun(sourceCode, 0, "D"); ABI_CHECK(callContractFunction("f()"), encodeArgs(1 | 2 | 4 | 8)); @@ -2495,9 +2495,9 @@ BOOST_AUTO_TEST_CASE(super_in_constructor) { char const* sourceCode = R"( contract A { function f() public returns (uint r) { return 1; } } - contract B is A { function f() public returns (uint r) { return super.f() | 2; } } - contract C is A { function f() public returns (uint r) { return super.f() | 4; } } - contract D is B, C { uint data; constructor() public { data = super.f() | 8; } function f() public returns (uint r) { return data; } } + contract B is A { function f() public override returns (uint r) { return super.f() | 2; } } + contract C is A { function f() public override returns (uint r) { return super.f() | 4; } } + contract D is B, C { uint data; constructor() public { data = super.f() | 8; } function f() public override (B, C) returns (uint r) { return data; } } )"; compileAndRun(sourceCode, 0, "D"); ABI_CHECK(callContractFunction("f()"), encodeArgs(1 | 2 | 4 | 8)); @@ -6018,9 +6018,11 @@ BOOST_AUTO_TEST_CASE(proper_order_of_overwriting_of_attributes) contract init_fix is init, fix { function checkOk() public returns (bool) { return ok; } + function isOk() public override (init, fix) returns (bool) { return super.isOk(); } } contract fix_init is fix, init { function checkOk() public returns (bool) { return ok; } + function isOk() public override (init, fix) returns (bool) { return super.isOk(); } } )"; compileAndRun(sourceCode, 0, "init_fix"); @@ -7983,7 +7985,7 @@ BOOST_AUTO_TEST_CASE(inherited_function) { char const* sourceCode = R"( contract A { function f() internal returns (uint) { return 1; } } contract B is A { - function f() internal returns (uint) { return 2; } + function f() internal override returns (uint) { return 2; } function g() public returns (uint) { return A.f(); } @@ -7998,7 +8000,7 @@ BOOST_AUTO_TEST_CASE(inherited_function_calldata_memory) { char const* sourceCode = R"( contract A { function f(uint[] calldata a) external returns (uint) { return a[0]; } } contract B is A { - function f(uint[] memory a) public returns (uint) { return a[1]; } + function f(uint[] memory a) public override returns (uint) { return a[1]; } function g() public returns (uint) { uint[] memory m = new uint[](2); m[0] = 42; @@ -8015,7 +8017,7 @@ BOOST_AUTO_TEST_CASE(inherited_function_calldata_memory) { BOOST_AUTO_TEST_CASE(inherited_function_calldata_memory_interface) { char const* sourceCode = R"( interface I { function f(uint[] calldata a) external returns (uint); } - contract A is I { function f(uint[] memory a) public returns (uint) { return 42; } } + contract A is I { function f(uint[] memory a) public override returns (uint) { return 42; } } contract B { function f(uint[] memory a) public returns (uint) { return a[1]; } function g() public returns (uint) { @@ -8032,7 +8034,7 @@ BOOST_AUTO_TEST_CASE(inherited_function_calldata_memory_interface) { BOOST_AUTO_TEST_CASE(inherited_function_calldata_calldata_interface) { char const* sourceCode = R"( interface I { function f(uint[] calldata a) external returns (uint); } - contract A is I { function f(uint[] calldata a) external returns (uint) { return 42; } } + contract A is I { function f(uint[] calldata a) external override returns (uint) { return 42; } } contract B { function f(uint[] memory a) public returns (uint) { return a[1]; } function g() public returns (uint) { @@ -12471,7 +12473,7 @@ BOOST_AUTO_TEST_CASE(interface_contract) } contract A is I { - function f() public returns (bool) { + function f() public override returns (bool) { return g(); } @@ -14479,7 +14481,7 @@ BOOST_AUTO_TEST_CASE(external_public_override) function f() external returns (uint) { return 1; } } contract B is A { - function f() public returns (uint) { return 2; } + function f() public override returns (uint) { return 2; } function g() public returns (uint) { return f(); } } )"; @@ -14647,7 +14649,7 @@ BOOST_AUTO_TEST_CASE(contract_name) } } contract D is C { - function name() public pure returns (string memory) { + function name() public override pure returns (string memory) { return type(D).name; } function name2() public pure returns (string memory) { diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 3a51672cf..414b913ec 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -65,7 +65,7 @@ BOOST_AUTO_TEST_CASE(abstract_contract) SourceUnit const* sourceUnit = nullptr; char const* text = R"( contract base { function foo() public; } - contract derived is base { function foo() public {} } + contract derived is base { function foo() public override {} } )"; sourceUnit = parseAndAnalyse(text); std::vector> nodes = sourceUnit->nodes(); diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp index dc3b18c88..749680b1f 100644 --- a/test/libsolidity/SolidityTypes.cpp +++ b/test/libsolidity/SolidityTypes.cpp @@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers) // TypeType is tested with contract auto emptyParams = make_shared(SourceLocation(), std::vector>()); - ModifierDefinition mod(SourceLocation{}, make_shared("modif"), {}, emptyParams, {}); + ModifierDefinition mod(SourceLocation{}, make_shared("modif"), {}, emptyParams, {}, {}); BOOST_CHECK_EQUAL(ModifierType(mod).identifier(), "t_modifier$__$"); SourceUnit su({}, {}); diff --git a/test/libsolidity/semanticTests/functionCall/base_base_overload.sol b/test/libsolidity/semanticTests/functionCall/base_base_overload.sol index ecc29b7a2..8091ad496 100644 --- a/test/libsolidity/semanticTests/functionCall/base_base_overload.sol +++ b/test/libsolidity/semanticTests/functionCall/base_base_overload.sol @@ -11,11 +11,11 @@ contract BaseBase { } contract Base is BaseBase { - function init(uint a, uint b) public { + function init(uint a, uint b) public override { x = a; y = b; } - function init(uint a) public { + function init(uint a) public override { x = a; } } diff --git a/test/libsolidity/semanticTests/viaYul/virtual_functions.sol b/test/libsolidity/semanticTests/viaYul/virtual_functions.sol index 4ca58e587..54b566779 100644 --- a/test/libsolidity/semanticTests/viaYul/virtual_functions.sol +++ b/test/libsolidity/semanticTests/viaYul/virtual_functions.sol @@ -19,7 +19,7 @@ contract C is X { // explicit call via base //x = super.g(); } - function g() public returns (uint x) { + function g() public override returns (uint x) { x = 3; } } diff --git a/test/libsolidity/syntaxTests/inheritance/override/add_view.sol b/test/libsolidity/syntaxTests/inheritance/override/add_view.sol index 21e437925..ffb8aa3f8 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/add_view.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/add_view.sol @@ -1,4 +1,5 @@ contract B { function f() public {} } contract C is B { function f() public view {} } // ---- +// TypeError: (56-83): Overriding function is missing 'override' specifier. // TypeError: (56-83): Overriding function changes state mutability from "nonpayable" to "view". diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory.sol index e683ef395..f5c3c237b 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory.sol @@ -6,8 +6,8 @@ contract A { function i(uint[] calldata) external payable {} } contract B is A { - function f(uint[] memory) public pure {} - function g(uint[] memory) public view { dummy; } - function h(uint[] memory) public { dummy = 42; } - function i(uint[] memory) public payable {} + function f(uint[] memory) public override pure {} + function g(uint[] memory) public override view { dummy; } + function h(uint[] memory) public override { dummy = 42; } + function i(uint[] memory) public override payable {} } diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_conflict.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_conflict.sol index dc734d36c..c8eb1c164 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_conflict.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_conflict.sol @@ -6,21 +6,17 @@ contract A { function i(uint[] calldata) external payable {} } contract B is A { - function f(uint[] calldata) external pure {} - function g(uint[] calldata) external view { dummy; } - function h(uint[] calldata) external { dummy = 42; } - function i(uint[] calldata) external payable {} - function f(uint[] memory) public pure {} - function g(uint[] memory) public view { dummy; } - function h(uint[] memory) public { dummy = 42; } - function i(uint[] memory) public payable {} + function f(uint[] calldata) external override pure {} + function g(uint[] calldata) external override view { dummy; } + function h(uint[] calldata) external override { dummy = 42; } + function i(uint[] calldata) external override payable {} + function f(uint[] memory) public override pure {} + function g(uint[] memory) public override view { dummy; } + function h(uint[] memory) public override { dummy = 42; } + function i(uint[] memory) public override payable {} } // ---- -// DeclarationError: (268-312): Function with same name and arguments defined twice. -// DeclarationError: (317-369): Function with same name and arguments defined twice. -// DeclarationError: (374-426): Function with same name and arguments defined twice. -// DeclarationError: (431-478): Function with same name and arguments defined twice. -// TypeError: (268-312): Overriding function visibility differs. -// TypeError: (317-369): Overriding function visibility differs. -// TypeError: (374-426): Overriding function visibility differs. -// TypeError: (431-478): Overriding function visibility differs. +// DeclarationError: (268-321): Function with same name and arguments defined twice. +// DeclarationError: (326-387): Function with same name and arguments defined twice. +// DeclarationError: (392-453): Function with same name and arguments defined twice. +// DeclarationError: (458-514): Function with same name and arguments defined twice. diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface.sol index 7eecc0797..7fe01073c 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface.sol @@ -6,8 +6,8 @@ interface I { } contract C is I { uint dummy; - function f(uint[] memory) public pure {} - function g(uint[] memory) public view { dummy; } - function h(uint[] memory) public { dummy = 42; } - function i(uint[] memory) public payable {} + function f(uint[] memory) public override pure {} + function g(uint[] memory) public override view { dummy; } + function h(uint[] memory) public override { dummy = 42; } + function i(uint[] memory) public override payable {} } diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_instantiate.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_instantiate.sol index 4cdc39246..0235c43ec 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_instantiate.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_instantiate.sol @@ -2,11 +2,11 @@ interface I { function f(uint[] calldata) external pure; } contract A is I { - function f(uint[] memory) public pure {} + function f(uint[] memory) public override pure {} } contract C { function f() public { I i = I(new A()); i.f(new uint[](1)); } -} \ No newline at end of file +} diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_struct.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_struct.sol index 49b27fd76..117546c21 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_struct.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_struct.sol @@ -8,10 +8,10 @@ interface I { } contract C is I { uint dummy; - function f(S memory) public pure {} - function g(S memory) public view { dummy; } - function h(S memory) public { dummy = 42; } - function i(S memory) public payable {} + function f(S memory) public override pure {} + function g(S memory) public override view { dummy; } + function h(S memory) public override { dummy = 42; } + function i(S memory) public override payable {} } // ---- // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_struct.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_struct.sol index 42aebf304..f6826656c 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_struct.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_struct.sol @@ -8,10 +8,10 @@ contract A { function i(S calldata) external payable {} } contract B is A { - function f(S memory) public pure {} - function g(S memory) public view { dummy; } - function h(S memory) public { dummy = 42; } - function i(S memory) public payable {} + function f(S memory) public override pure {} + function g(S memory) public override view { dummy; } + function h(S memory) public override { dummy = 42; } + function i(S memory) public override payable {} } // ---- // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. diff --git a/test/libsolidity/syntaxTests/inheritance/override/change_return_types_in_interface.sol b/test/libsolidity/syntaxTests/inheritance/override/change_return_types_in_interface.sol index 804a18108..1a3f89d6d 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/change_return_types_in_interface.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/change_return_types_in_interface.sol @@ -7,4 +7,5 @@ contract B is I { function f() public pure returns (uint, uint) {} } // ---- +// TypeError: (182-230): Overriding function is missing 'override' specifier. // TypeError: (182-230): Overriding function return types differ. diff --git a/test/libsolidity/syntaxTests/inheritance/override/external_turns_public_no_params.sol b/test/libsolidity/syntaxTests/inheritance/override/external_turns_public_no_params.sol index 3d0394f5e..af2c56521 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/external_turns_public_no_params.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/external_turns_public_no_params.sol @@ -2,6 +2,6 @@ contract A { function f() external pure {} } contract B is A { - function f() public pure { + function f() public override pure { } } diff --git a/test/libsolidity/syntaxTests/inheritance/override/internal_external.sol b/test/libsolidity/syntaxTests/inheritance/override/internal_external.sol index 90973ee79..186909dae 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/internal_external.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/internal_external.sol @@ -4,4 +4,3 @@ contract A { } // ---- // DeclarationError: (17-61): Function with same name and arguments defined twice. -// TypeError: (17-61): Overriding function visibility differs. diff --git a/test/libsolidity/syntaxTests/inheritance/override/internal_external_inheritance.sol b/test/libsolidity/syntaxTests/inheritance/override/internal_external_inheritance.sol index c09a80001..b744add00 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/internal_external_inheritance.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/internal_external_inheritance.sol @@ -6,4 +6,4 @@ contract B { } contract C is A, B {} // ---- -// TypeError: (81-123): Overriding function visibility differs. +// TypeError: (126-147): Derived contract must override function "f". Function with the same name and parameter types defined in two or more base classes. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override.sol b/test/libsolidity/syntaxTests/inheritance/override/override.sol index bb7aa7347..d597c6463 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/override.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/override.sol @@ -1,5 +1,11 @@ -contract X { +contract A { + int public testvar; + function test() internal returns (uint256); + function test2() internal returns (uint256); +} +contract X is A { int public override testvar; function test() internal override returns (uint256); + function test2() internal override(A) returns (uint256); } // ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_ambiguous.sol b/test/libsolidity/syntaxTests/inheritance/override/override_ambiguous.sol new file mode 100644 index 000000000..ca94b2ea6 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_ambiguous.sol @@ -0,0 +1,14 @@ +contract A { + int public testvar; + function foo() internal returns (uint256); +} +contract B { + function foo() internal returns (uint256); + function test() internal returns (uint256); +} +contract X is A, B { + int public override testvar; + function test() internal override returns (uint256); +} +// ---- +// TypeError: (184-290): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_base_base.sol b/test/libsolidity/syntaxTests/inheritance/override/override_base_base.sol new file mode 100644 index 000000000..7d85f5fca --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_base_base.sol @@ -0,0 +1,20 @@ +contract A { + function foo() internal returns (uint256); +} + +contract B is A { + function foo() internal override returns (uint256); +} + +contract C is B { + function foo() internal override returns (uint256); +} + +contract D is C { + function foo() internal override returns (uint256); +} + +contract X is D { + function foo() internal override returns (uint256); +} +// ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_multiple.sol b/test/libsolidity/syntaxTests/inheritance/override/override_multiple.sol index 0b16056a6..90e2c2968 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/override_multiple.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/override_multiple.sol @@ -1,9 +1,21 @@ contract A { + int public testvar; + function foo() internal returns (uint256); + function test(uint8 _a) internal returns (uint256); +} +contract B { + function foo() internal returns (uint256); + function test() internal returns (uint256); +} +contract C { function foo() internal returns (uint256); } -contract X { +contract D { + function foo() internal returns (uint256); +} +contract X is A, B, C, D { int public override testvar; function test() internal override returns (uint256); - function foo() internal override(X, A) returns (uint256); + function foo() internal override(A, B, C, D) returns (uint256); } // ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_multiple2.sol b/test/libsolidity/syntaxTests/inheritance/override/override_multiple2.sol new file mode 100644 index 000000000..050d998e7 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_multiple2.sol @@ -0,0 +1,15 @@ +contract A { + int public testvar; + function foo() internal returns (uint256); + function test(uint8 _a) internal returns (uint256); +} +contract B { + function foo() internal returns (uint256); +} + +contract C is A { +} +contract D is A, B, C { + function foo() internal override(A, B) returns (uint256); +} +// ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_multiple_duplicated.sol b/test/libsolidity/syntaxTests/inheritance/override/override_multiple_duplicated.sol new file mode 100644 index 000000000..0a3d6c572 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_multiple_duplicated.sol @@ -0,0 +1,26 @@ +contract A { + int public testvar; + function foo() internal returns (uint256); + function test(uint8 _a) internal returns (uint256); +} +contract B { + function foo() internal returns (uint256); + function test() internal returns (uint256); +} +contract C { + function foo() internal returns (uint256); +} +contract D { + function foo() internal returns (uint256); + function test() internal returns (uint256); +} +contract X is A, B, C, D { + int public override testvar; + function test() internal override(B, D, D) returns (uint256); + function foo() internal override(A, C, B, B, B, D ,D) returns (uint256); +} +// ---- +// TypeError: (498-499): Duplicate contract "D" found in override list of "test". +// TypeError: (563-564): Duplicate contract "B" found in override list of "foo". +// TypeError: (566-567): Duplicate contract "B" found in override list of "foo". +// TypeError: (572-573): Duplicate contract "D" found in override list of "foo". diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_multiple_missing.sol b/test/libsolidity/syntaxTests/inheritance/override/override_multiple_missing.sol new file mode 100644 index 000000000..b1df2a3a0 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_multiple_missing.sol @@ -0,0 +1,24 @@ +contract A { + int public testvar; + function foo() internal returns (uint256); + function test(uint8 _a) internal returns (uint256); +} +contract B { + function foo() internal returns (uint256); + function test() internal returns (uint256); +} +contract C { + function foo() internal returns (uint256); +} +contract D { + function foo() internal returns (uint256); + function test() internal returns (uint256); +} +contract X is A, B, C, D { + int public override testvar; + function test() internal override(B, D, C) returns (uint256); + function foo() internal override(A, C) returns (uint256); +} +// ---- +// TypeError: (483-500): Invalid contract specified in override list: C. +// TypeError: (545-559): Function needs to specify overridden contracts B and D. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_multiple_unresolved.sol b/test/libsolidity/syntaxTests/inheritance/override/override_multiple_unresolved.sol new file mode 100644 index 000000000..d4fbabda2 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_multiple_unresolved.sol @@ -0,0 +1,6 @@ +contract A { + int public testvar; + function foo() internal override(N, Z) returns (uint256); +} +// ---- +// DeclarationError: (68-69): Identifier not found or not unique. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_return_mismatch.sol b/test/libsolidity/syntaxTests/inheritance/override/override_return_mismatch.sol new file mode 100644 index 000000000..5cbbe4f35 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_return_mismatch.sol @@ -0,0 +1,14 @@ +contract A { + int public testvar; + function foo() internal returns (uint256); +} +contract B { + function foo() internal returns (uint8); + function test() internal returns (uint256); +} +contract X is A, B { + int public override testvar; + function test() internal override returns (uint256); +} +// ---- +// TypeError: (182-288): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_shared_base.sol b/test/libsolidity/syntaxTests/inheritance/override/override_shared_base.sol new file mode 100644 index 000000000..58926ecc6 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_shared_base.sol @@ -0,0 +1,15 @@ +contract I { + function set() public {} +} +contract A is I { + uint a; + function set() public override { a = 1; super.set(); a = 2; } +} +contract B is I { + uint b; + function set() public override { b = 1; super.set(); b = 2; } + +} +contract X is A, B { + function set() public override(A, B) { super.set(); } +} diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_shared_base_partial.sol b/test/libsolidity/syntaxTests/inheritance/override/override_shared_base_partial.sol new file mode 100644 index 000000000..6efacc951 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_shared_base_partial.sol @@ -0,0 +1,10 @@ +contract I { + function f() external {} +} +contract A is I { + function f() external override {} +} +contract B is I {} +contract C is A, B { + function f() external override(A, I) {} +} diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_shared_base_simple.sol b/test/libsolidity/syntaxTests/inheritance/override/override_shared_base_simple.sol new file mode 100644 index 000000000..f0bf1f49a --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_shared_base_simple.sol @@ -0,0 +1,6 @@ +contract I { + function f() external {} +} +contract A is I {} +contract B is I {} +contract C is A, B {} diff --git a/test/libsolidity/syntaxTests/inheritance/override/remove_view.sol b/test/libsolidity/syntaxTests/inheritance/override/remove_view.sol index cc785858c..63e1f8534 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/remove_view.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/remove_view.sol @@ -1,4 +1,5 @@ contract B { function f() public view {} } contract C is B { function f() public {} } // ---- +// TypeError: (61-83): Overriding function is missing 'override' specifier. // TypeError: (61-83): Overriding function changes state mutability from "view" to "nonpayable". diff --git a/test/libsolidity/syntaxTests/inheritance/super_on_external.sol b/test/libsolidity/syntaxTests/inheritance/super_on_external.sol index 21f3b1c2e..b83205bec 100644 --- a/test/libsolidity/syntaxTests/inheritance/super_on_external.sol +++ b/test/libsolidity/syntaxTests/inheritance/super_on_external.sol @@ -2,9 +2,9 @@ contract A { function f() external pure {} } contract B is A { - function f() public pure { + function f() public override pure { super.f(); } } // ---- -// TypeError: (106-113): Member "f" not found or not visible after argument-dependent lookup in contract super B. +// TypeError: (115-122): Member "f" not found or not visible after argument-dependent lookup in contract super B. diff --git a/test/libsolidity/syntaxTests/modifiers/illegal_modifier_override.sol b/test/libsolidity/syntaxTests/modifiers/illegal_modifier_override.sol index 958be686c..3abac89c1 100644 --- a/test/libsolidity/syntaxTests/modifiers/illegal_modifier_override.sol +++ b/test/libsolidity/syntaxTests/modifiers/illegal_modifier_override.sol @@ -1,4 +1,5 @@ contract A { modifier mod(uint a) { _; } } contract B is A { modifier mod(uint8 a) { _; } } // ---- +// TypeError: (61-89): Overriding modifier is missing 'override' specifier. // TypeError: (61-89): Override changes modifier signature. diff --git a/test/libsolidity/syntaxTests/modifiers/modifier_overrides_function.sol b/test/libsolidity/syntaxTests/modifiers/modifier_overrides_function.sol index a43646c33..85ca6c20a 100644 --- a/test/libsolidity/syntaxTests/modifiers/modifier_overrides_function.sol +++ b/test/libsolidity/syntaxTests/modifiers/modifier_overrides_function.sol @@ -2,4 +2,4 @@ contract A { modifier mod(uint a) { _; } } contract B is A { function mod(uint a) public { } } // ---- // DeclarationError: (61-92): Identifier already declared. -// TypeError: (13-40): Override changes modifier to function. +// TypeError: (61-92): Override changes modifier to function. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/030_redeclare_implemented_abstract_function_as_abstract.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/030_redeclare_implemented_abstract_function_as_abstract.sol index 55bdea894..8e78c5c2a 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/030_redeclare_implemented_abstract_function_as_abstract.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/030_redeclare_implemented_abstract_function_as_abstract.sol @@ -1,5 +1,6 @@ contract base { function foo() public; } -contract derived is base { function foo() public {} } +contract derived is base { function foo() public override {} } contract wrong is derived { function foo() public; } // ---- -// TypeError: (123-145): Redeclaring an already implemented function as abstract +// TypeError: (132-154): Overriding function is missing 'override' specifier. +// TypeError: (132-154): Redeclaring an already implemented function as abstract diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/055_inheritance_diamond_basic.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/055_inheritance_diamond_basic.sol index 2e235ee0f..b102c00fe 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/055_inheritance_diamond_basic.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/055_inheritance_diamond_basic.sol @@ -2,6 +2,7 @@ contract root { function rootFunction() public {} } contract inter1 is root { function f() public {} } contract inter2 is root { function f() public {} } contract derived is root, inter2, inter1 { - function g() public { f(); rootFunction(); } + function g() public { f(); rootFunction(); } + function f() override(inter1, inter2) public {} } // ---- diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/059_illegal_override_visibility.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/059_illegal_override_visibility.sol index 8c13a4785..bbc27d1c7 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/059_illegal_override_visibility.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/059_illegal_override_visibility.sol @@ -1,4 +1,5 @@ contract B { function f() internal {} } contract C is B { function f() public {} } // ---- +// TypeError: (58-80): Overriding function is missing 'override' specifier. // TypeError: (58-80): Overriding function visibility differs. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/060_complex_inheritance.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/060_complex_inheritance.sol index ce3b622b1..19029f570 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/060_complex_inheritance.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/060_complex_inheritance.sol @@ -1,5 +1,5 @@ contract A { function f() public { uint8 x = C(0).g(); } } contract B { function f() public {} function g() public returns (uint8) {} } -contract C is A, B { } +contract C is A, B { function f() public override (A, B) { A.f(); } } // ---- // Warning: (35-42): Unused local variable. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/079_fallback_function_inheritance.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/079_fallback_function_inheritance.sol index c8c06c6ec..690ab5bfd 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/079_fallback_function_inheritance.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/079_fallback_function_inheritance.sol @@ -3,5 +3,5 @@ contract A { function() external { x = 1; } } contract C is A { - function() external { x = 2; } + function() override external { x = 2; } } diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/149_test_for_bug_override_function_with_bytearray_type.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/149_test_for_bug_override_function_with_bytearray_type.sol index bc1c42674..59fbcde1e 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/149_test_for_bug_override_function_with_bytearray_type.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/149_test_for_bug_override_function_with_bytearray_type.sol @@ -2,7 +2,7 @@ contract Vehicle { function f(bytes calldata) external returns (uint256 r) {r = 1;} } contract Bike is Vehicle { - function f(bytes calldata) external returns (uint256 r) {r = 42;} + function f(bytes calldata) override external returns (uint256 r) {r = 42;} } // ---- // Warning: (23-87): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/181_override_changes_return_types.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/181_override_changes_return_types.sol index c887f2597..5a5c932f4 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/181_override_changes_return_types.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/181_override_changes_return_types.sol @@ -2,7 +2,7 @@ contract base { function f(uint a) public returns (uint) { } } contract test is base { - function f(uint a) public returns (uint8) { } + function f(uint a) public override returns (uint8) { } } // ---- -// TypeError: (95-140): Overriding function return types differ. +// TypeError: (95-149): Overriding function return types differ. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/182_equal_overload.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/182_equal_overload.sol index 865855184..6f0c7df79 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/182_equal_overload.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/182_equal_overload.sol @@ -4,4 +4,3 @@ contract C { } // ---- // DeclarationError: (17-66): Function with same name and arguments defined twice. -// TypeError: (17-66): Overriding function return types differ. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/358_illegal_override_payable.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/358_illegal_override_payable.sol index 6696772e8..a5d0f1aab 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/358_illegal_override_payable.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/358_illegal_override_payable.sol @@ -1,4 +1,5 @@ contract B { function f() payable public {} } contract C is B { function f() public {} } // ---- +// TypeError: (64-86): Overriding function is missing 'override' specifier. // TypeError: (64-86): Overriding function changes state mutability from "payable" to "nonpayable". diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/359_illegal_override_payable_nonpayable.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/359_illegal_override_payable_nonpayable.sol index 99b45fdda..6a49ca24f 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/359_illegal_override_payable_nonpayable.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/359_illegal_override_payable_nonpayable.sol @@ -1,4 +1,5 @@ contract B { function f() public {} } contract C is B { function f() payable public {} } // ---- +// TypeError: (56-86): Overriding function is missing 'override' specifier. // TypeError: (56-86): Overriding function changes state mutability from "nonpayable" to "payable". diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/423_using_interface.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/423_using_interface.sol index d576bb601..4f7cf1899 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/423_using_interface.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/423_using_interface.sol @@ -2,7 +2,7 @@ interface I { function f() external; } contract C is I { - function f() public { + function f() public override { } } // ---- diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/424_using_interface_complex.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/424_using_interface_complex.sol index a3dca996a..58df3dd78 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/424_using_interface_complex.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/424_using_interface_complex.sol @@ -5,7 +5,7 @@ interface I { function() external; } contract C is I { - function f() public { + function f() public override { } } // ---- diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/425_interface_implement_public_contract.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/425_interface_implement_public_contract.sol index d85402887..0ffd95804 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/425_interface_implement_public_contract.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/425_interface_implement_public_contract.sol @@ -2,6 +2,6 @@ interface I { function f() external; } contract C is I { - function f() public { + function f() public override { } } diff --git a/test/libsolidity/syntaxTests/unimplemented_super_function.sol b/test/libsolidity/syntaxTests/unimplemented_super_function.sol index 356727ae4..230d0e60d 100644 --- a/test/libsolidity/syntaxTests/unimplemented_super_function.sol +++ b/test/libsolidity/syntaxTests/unimplemented_super_function.sol @@ -2,7 +2,7 @@ contract a { function f() public; } contract b is a { - function f() public { super.f(); } + function f() public override { super.f(); } } // ---- -// TypeError: (84-91): Member "f" not found or not visible after argument-dependent lookup in contract super b. +// TypeError: (93-100): Member "f" not found or not visible after argument-dependent lookup in contract super b. diff --git a/test/libsolidity/syntaxTests/unimplemented_super_function_derived.sol b/test/libsolidity/syntaxTests/unimplemented_super_function_derived.sol index 88acbdf0d..a66f75cd3 100644 --- a/test/libsolidity/syntaxTests/unimplemented_super_function_derived.sol +++ b/test/libsolidity/syntaxTests/unimplemented_super_function_derived.sol @@ -2,11 +2,11 @@ contract a { function f() public; } contract b is a { - function f() public { super.f(); } + function f() public override { super.f(); } } contract c is a,b { // No error here. - function f() public { super.f(); } + function f() public override(a, b) { super.f(); } } // ---- -// TypeError: (84-91): Member "f" not found or not visible after argument-dependent lookup in contract super b. +// TypeError: (93-100): Member "f" not found or not visible after argument-dependent lookup in contract super b. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/interface.sol b/test/libsolidity/syntaxTests/viewPureChecker/interface.sol index 0874e78a2..c2f70b3c6 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/interface.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/interface.sol @@ -2,5 +2,5 @@ interface D { function f() view external; } contract C is D { - function f() view external {} + function f() override view external {} } diff --git a/test/libsolidity/syntaxTests/viewPureChecker/overriding_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/overriding_fail.sol index 61702495b..6aed3c595 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/overriding_fail.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/overriding_fail.sol @@ -4,13 +4,13 @@ contract D { function g() public pure {} } contract C1 is D { - function f() public {} - function g() public view {} + function f() public override {} + function g() public override view {} } contract C2 is D { - function g() public {} + function g() public override {} } // ---- -// TypeError: (118-140): Overriding function changes state mutability from "view" to "nonpayable". -// TypeError: (145-172): Overriding function changes state mutability from "pure" to "view". -// TypeError: (198-220): Overriding function changes state mutability from "pure" to "nonpayable". +// TypeError: (118-149): Overriding function changes state mutability from "view" to "nonpayable". +// TypeError: (154-190): Overriding function changes state mutability from "pure" to "view". +// TypeError: (216-247): Overriding function changes state mutability from "pure" to "nonpayable". diff --git a/test/libsolidity/syntaxTests/viewPureChecker/overriding_no_restrict_warning.sol b/test/libsolidity/syntaxTests/viewPureChecker/overriding_no_restrict_warning.sol index c82c79083..78cbb4519 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/overriding_no_restrict_warning.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/overriding_no_restrict_warning.sol @@ -3,5 +3,5 @@ contract D { function f() public { x = 2; } } contract C is D { - function f() public {} + function f() public override {} }