diff options
-rw-r--r-- | AST.cpp | 18 | ||||
-rw-r--r-- | DeclarationContainer.cpp | 42 | ||||
-rw-r--r-- | DeclarationContainer.h | 4 | ||||
-rw-r--r-- | Exceptions.h | 17 | ||||
-rw-r--r-- | NameAndTypeResolver.cpp | 12 | ||||
-rw-r--r-- | SourceReferenceFormatter.cpp | 33 | ||||
-rw-r--r-- | SourceReferenceFormatter.h | 2 |
7 files changed, 100 insertions, 28 deletions
@@ -140,12 +140,22 @@ void ContractDefinition::checkDuplicateFunctions() const map<string, vector<FunctionDefinition const*>> functions; for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions()) functions[function->getName()].push_back(function.get()); + if (functions[getName()].size() > 1) + { + SecondarySourceLocation ssl; + auto it = functions[getName()].begin(); + ++it; + for(; it != functions[getName()].end(); ++it) + ssl.append("Another declaration is here:", (*it)->getLocation()); + BOOST_THROW_EXCEPTION( DeclarationError() << - errinfo_sourceLocation(getLocation()) << - errinfo_comment("More than one constructor defined.") + errinfo_sourceLocation(getConstructor()->getLocation()) << + errinfo_comment("More than one constructor defined.") << + errinfo_secondarySourceLocation(ssl) ); + } for (auto const& it: functions) { vector<FunctionDefinition const*> const& overloads = it.second; @@ -155,7 +165,9 @@ void ContractDefinition::checkDuplicateFunctions() const BOOST_THROW_EXCEPTION( DeclarationError() << errinfo_sourceLocation(overloads[j]->getLocation()) << - errinfo_comment("Function with same name and arguments already defined.") + errinfo_comment("Function with same name and arguments already defined.") << + errinfo_secondarySourceLocation(SecondarySourceLocation().append( + "The previous declaration is here:", overloads[i]->getLocation())) ); } } diff --git a/DeclarationContainer.cpp b/DeclarationContainer.cpp index 2130f3a0..c836663c 100644 --- a/DeclarationContainer.cpp +++ b/DeclarationContainer.cpp @@ -28,6 +28,28 @@ using namespace std; using namespace dev; using namespace dev::solidity; +Declaration const* DeclarationContainer::conflictingDeclaration(Declaration const& _declaration) const +{ + ASTString const& name(_declaration.getName()); + solAssert(!name.empty(), ""); + vector<Declaration const*> declarations; + if (m_declarations.count(name)) + declarations += m_declarations.at(name); + if (m_invisibleDeclarations.count(name)) + declarations += m_invisibleDeclarations.at(name); + if (dynamic_cast<FunctionDefinition const*>(&_declaration)) + { + // check that all other declarations with the same name are functions + for (Declaration const* declaration: declarations) + if (!dynamic_cast<FunctionDefinition const*>(declaration)) + return declaration; + } + else if (!declarations.empty()) + return declarations.front(); + + return nullptr; +} + bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update) { ASTString const& name(_declaration.getName()); @@ -40,24 +62,8 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, m_declarations.erase(name); m_invisibleDeclarations.erase(name); } - else - { - vector<Declaration const*> declarations; - if (m_declarations.count(name)) - declarations += m_declarations.at(name); - if (m_invisibleDeclarations.count(name)) - declarations += m_invisibleDeclarations.at(name); - if (dynamic_cast<FunctionDefinition const*>(&_declaration)) - { - // check that all other declarations with the same name are functions - - for (Declaration const* declaration: declarations) - if (!dynamic_cast<FunctionDefinition const*>(declaration)) - return false; - } - else if (!declarations.empty()) - return false; - } + else if (conflictingDeclaration(_declaration)) + return false; if (_invisible) m_invisibleDeclarations[name].insert(&_declaration); diff --git a/DeclarationContainer.h b/DeclarationContainer.h index 35a6ea07..9ae25880 100644 --- a/DeclarationContainer.h +++ b/DeclarationContainer.h @@ -34,7 +34,7 @@ namespace solidity { /** - * Container that stores mappings betwee names and declarations. It also contains a link to the + * Container that stores mappings between names and declarations. It also contains a link to the * enclosing scope. */ class DeclarationContainer @@ -51,6 +51,8 @@ public: std::set<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const; Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } std::map<ASTString, std::set<Declaration const*>> const& getDeclarations() const { return m_declarations; } + /// @returns weather declaration is valid, and if not also returns previous declaration. + Declaration const* conflictingDeclaration(Declaration const& _declaration) const; private: Declaration const* m_enclosingDeclaration; diff --git a/Exceptions.h b/Exceptions.h index 0d07c706..51106c2b 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -23,6 +23,7 @@ #pragma once #include <string> +#include <utility> #include <libdevcore/Exceptions.h> #include <libevmcore/SourceLocation.h> @@ -38,7 +39,23 @@ struct CompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {}; struct DocstringParsingError: virtual Exception {}; +using errorSourceLocationInfo = std::pair<std::string, SourceLocation>; + +class SecondarySourceLocation +{ +public: + //SecondarySourceLocation(){} + SecondarySourceLocation& append(std::string const& _errMsg, SourceLocation const& _sourceLocation) + { + infos.push_back(std::make_pair(_errMsg, _sourceLocation)); + return *this; + } + + std::vector<errorSourceLocationInfo> infos; +}; + using errinfo_sourceLocation = boost::error_info<struct tag_sourceLocation, SourceLocation>; +using errinfo_secondarySourceLocation = boost::error_info<struct tag_secondarySourceLocation, SecondarySourceLocation>; } } diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp index a286934a..56e81e37 100644 --- a/NameAndTypeResolver.cpp +++ b/NameAndTypeResolver.cpp @@ -354,8 +354,16 @@ void DeclarationRegistrationHelper::closeCurrentScope() void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract())) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) - << errinfo_comment("Identifier already declared.")); + { + solAssert(m_scopes[m_currentScope].conflictingDeclaration(_declaration), ""); + BOOST_THROW_EXCEPTION(DeclarationError() + << errinfo_sourceLocation(_declaration.getLocation()) + << errinfo_comment("Identifier already declared.") + << errinfo_secondarySourceLocation(SecondarySourceLocation().append( + "The previous declaration is here:", + m_scopes[m_currentScope].conflictingDeclaration(_declaration)->getLocation()))); + } + //@todo the exception should also contain the location of the first declaration _declaration.setScope(m_currentScope); if (_opensScope) diff --git a/SourceReferenceFormatter.cpp b/SourceReferenceFormatter.cpp index b5e83b8c..a30621a1 100644 --- a/SourceReferenceFormatter.cpp +++ b/SourceReferenceFormatter.cpp @@ -64,28 +64,53 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream, << "Spanning multiple lines.\n"; } +void SourceReferenceFormatter::printSourceName(ostream& _stream, + SourceLocation const& _location, + Scanner const& _scanner) +{ + int startLine; + int startColumn; + tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); + _stream << *_location.sourceName << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": "; +} + void SourceReferenceFormatter::printExceptionInformation(ostream& _stream, Exception const& _exception, string const& _name, CompilerStack const& _compiler) { SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception); + auto secondarylocation = boost::get_error_info<errinfo_secondarySourceLocation>(_exception); Scanner const* scanner; if (location) { scanner = &_compiler.getScanner(*location->sourceName); - int startLine; - int startColumn; - tie(startLine, startColumn) = scanner->translatePositionToLineColumn(location->start); - _stream << *location->sourceName << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": "; + printSourceName(_stream, *location, *scanner); } + _stream << _name; if (string const* description = boost::get_error_info<errinfo_comment>(_exception)) _stream << ": " << *description << endl; if (location) + { + solAssert(scanner, ""); printSourceLocation(_stream, *location, *scanner); + } + + if (secondarylocation && !secondarylocation->infos.empty()) + { + for(auto info: secondarylocation->infos) + { + scanner = &_compiler.getScanner(*info.second.sourceName); + _stream << info.first << " "; + printSourceName(_stream, info.second, *scanner); + _stream << endl; + printSourceLocation(_stream, info.second, *scanner); + } + _stream << endl; + } } } diff --git a/SourceReferenceFormatter.h b/SourceReferenceFormatter.h index 304e6a27..43d3882e 100644 --- a/SourceReferenceFormatter.h +++ b/SourceReferenceFormatter.h @@ -42,6 +42,8 @@ public: static void printSourceLocation(std::ostream& _stream, SourceLocation const& _location, Scanner const& _scanner); static void printExceptionInformation(std::ostream& _stream, Exception const& _exception, std::string const& _name, CompilerStack const& _compiler); +private: + static void printSourceName(std::ostream& _stream, SourceLocation const& _location, Scanner const& _scanner); }; } |