diff options
author | Alex Beregszaszi <alex@rtfs.hu> | 2017-08-12 06:06:00 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-12 06:06:00 +0800 |
commit | 52ccc264940c00ae8ffe015433bc1d094c1a4f1f (patch) | |
tree | 68d25d1f062ed105c7ab0d6eb7970540c6f4ae3d | |
parent | d968912a4ce89a40d7d03bf0748a07c397662f68 (diff) | |
parent | 3571db6e3f54476cdabaf4861100564ae4b00a6a (diff) | |
download | dexon-solidity-52ccc264940c00ae8ffe015433bc1d094c1a4f1f.tar.gz dexon-solidity-52ccc264940c00ae8ffe015433bc1d094c1a4f1f.tar.zst dexon-solidity-52ccc264940c00ae8ffe015433bc1d094c1a4f1f.zip |
Merge pull request #2581 from federicobond/improve-override-error
Improve override function error messages
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 54 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.h | 3 | ||||
-rw-r--r-- | libsolidity/ast/AST.cpp | 9 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 1 | ||||
-rw-r--r-- | libsolidity/interface/ErrorReporter.h | 4 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 21 |
7 files changed, 70 insertions, 23 deletions
diff --git a/Changelog.md b/Changelog.md index 4609da92..b4ca745f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,7 @@ Features: * Parser: Display previous visibility specifier in error if multiple are found. * Syntax Checker: Support ``pragma experimental <feature>;`` to turn on experimental features. * Metadata: Store experimental flag in metadata CBOR. + * Type Checker: More detailed error message for invalid overrides. Bugfixes: * Parser: Enforce commas between array and tuple elements. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 6852c13d..8dd45a90 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -277,21 +277,10 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr string const& name = function->name(); if (modifiers.count(name)) m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier."); - FunctionType functionType(*function); - // function should not change the return type + for (FunctionDefinition const* overriding: functions[name]) - { - FunctionType overridingType(*overriding); - if (!overridingType.hasEqualArgumentTypes(functionType)) - continue; - if ( - overriding->visibility() != function->visibility() || - overriding->isDeclaredConst() != function->isDeclaredConst() || - overriding->isPayable() != function->isPayable() || - overridingType != functionType - ) - m_errorReporter.typeError(overriding->location(), "Override changes extended function signature."); - } + checkFunctionOverride(*overriding, *function); + functions[name].push_back(function); } for (ModifierDefinition const* modifier: contract->functionModifiers()) @@ -308,6 +297,42 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr } } +void TypeChecker::checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super) +{ + FunctionType functionType(function); + FunctionType superType(super); + + if (!functionType.hasEqualArgumentTypes(superType)) + return; + + if (function.visibility() != super.visibility()) + overrideError(function, super, "Overriding function visibility differs."); + + else if (function.isDeclaredConst() && !super.isDeclaredConst()) + overrideError(function, super, "Overriding function should not be declared constant."); + + else if (!function.isDeclaredConst() && super.isDeclaredConst()) + overrideError(function, super, "Overriding function should be declared constant."); + + else if (function.isPayable() && !super.isPayable()) + overrideError(function, super, "Overriding function should not be declared payable."); + + else if (!function.isPayable() && super.isPayable()) + overrideError(function, super, "Overriding function should be declared payable."); + + else if (functionType != superType) + overrideError(function, super, "Overriding function return types differ."); +} + +void TypeChecker::overrideError(FunctionDefinition const& function, FunctionDefinition const& super, string message) +{ + m_errorReporter.typeError( + function.location(), + SecondarySourceLocation().append("Overriden function is here:", super.location()), + message + ); +} + void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _contract) { map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations; @@ -1949,4 +1974,3 @@ void TypeChecker::requireLValue(Expression const& _expression) else if (!_expression.annotation().isLValue) m_errorReporter.typeError(_expression.location(), "Expression has to be an lvalue."); } - diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index ee43d13a..f2e13765 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -62,6 +62,9 @@ private: /// arguments and that there is at most one constructor. void checkContractDuplicateFunctions(ContractDefinition const& _contract); void checkContractIllegalOverrides(ContractDefinition const& _contract); + /// Reports a type error with an appropiate message if overriden function signature differs. + void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super); + void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message); void checkContractAbstractFunctions(ContractDefinition const& _contract); void checkContractAbstractConstructors(ContractDefinition const& _contract); /// Checks that different functions with external visibility end up having different diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 1d68231e..e173237e 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -371,6 +371,15 @@ string FunctionDefinition::externalSignature() const return FunctionType(*this).externalSignature(); } +string FunctionDefinition::fullyQualifiedName() const +{ + auto const* contract = dynamic_cast<ContractDefinition const*>(scope()); + solAssert(contract, "Enclosing scope of function definition was not set."); + + auto fname = name().empty() ? "<fallback>" : name(); + return sourceUnitName() + ":" + contract->name() + "." + fname; +} + FunctionDefinitionAnnotation& FunctionDefinition::annotation() const { if (!m_annotation) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index bdf20e81..d32cf573 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -613,6 +613,7 @@ public: std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; } std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); } Block const& body() const { solAssert(m_body, ""); return *m_body; } + std::string fullyQualifiedName() const; virtual bool isVisibleInContract() const override { return Declaration::isVisibleInContract() && !isConstructor() && !isFallback(); diff --git a/libsolidity/interface/ErrorReporter.h b/libsolidity/interface/ErrorReporter.h index 42b0c8b6..12f4e8df 100644 --- a/libsolidity/interface/ErrorReporter.h +++ b/libsolidity/interface/ErrorReporter.h @@ -75,8 +75,8 @@ public: void typeError( SourceLocation const& _location, - SecondarySourceLocation const& _secondaryLocation, - std::string const& _description + SecondarySourceLocation const& _secondaryLocation = SecondarySourceLocation(), + std::string const& _description = std::string() ); void typeError(SourceLocation const& _location, std::string const& _description); diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index f7648bd7..49a23e13 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -924,16 +924,25 @@ BOOST_AUTO_TEST_CASE(illegal_override_visibility) contract B { function f() internal {} } contract C is B { function f() public {} } )"; - CHECK_ERROR(text, TypeError, "Override changes extended function signature."); + CHECK_ERROR(text, TypeError, "Overriding function visibility differs"); } -BOOST_AUTO_TEST_CASE(illegal_override_constness) +BOOST_AUTO_TEST_CASE(illegal_override_remove_constness) { char const* text = R"( contract B { function f() constant {} } contract C is B { function f() {} } )"; - CHECK_ERROR(text, TypeError, "Override changes extended function signature."); + CHECK_ERROR(text, TypeError, "Overriding function should be declared constant."); +} + +BOOST_AUTO_TEST_CASE(illegal_override_add_constness) +{ + char const* text = R"( + contract B { function f() {} } + contract C is B { function f() constant {} } + )"; + CHECK_ERROR(text, TypeError, "Overriding function should not be declared constant."); } BOOST_AUTO_TEST_CASE(complex_inheritance) @@ -2491,7 +2500,7 @@ BOOST_AUTO_TEST_CASE(override_changes_return_types) function f(uint a) returns (uint8) { } } )"; - CHECK_ERROR(sourceCode, TypeError, "Override changes extended function signature."); + CHECK_ERROR(sourceCode, TypeError, "Overriding function return types differ"); } BOOST_AUTO_TEST_CASE(multiple_constructors) @@ -4732,7 +4741,7 @@ BOOST_AUTO_TEST_CASE(illegal_override_payable) contract B { function f() payable {} } contract C is B { function f() {} } )"; - CHECK_ERROR(text, TypeError, "Override changes extended function signature."); + CHECK_ERROR(text, TypeError, "Overriding function should be declared payable."); } BOOST_AUTO_TEST_CASE(illegal_override_payable_nonpayable) @@ -4741,7 +4750,7 @@ BOOST_AUTO_TEST_CASE(illegal_override_payable_nonpayable) contract B { function f() {} } contract C is B { function f() payable {} } )"; - CHECK_ERROR(text, TypeError, "Override changes extended function signature."); + CHECK_ERROR(text, TypeError, "Overriding function should not be declared payable."); } BOOST_AUTO_TEST_CASE(function_variable_mixin) |