aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AST.cpp18
-rw-r--r--DeclarationContainer.cpp42
-rw-r--r--DeclarationContainer.h4
-rw-r--r--Exceptions.h17
-rw-r--r--NameAndTypeResolver.cpp12
-rw-r--r--SourceReferenceFormatter.cpp33
-rw-r--r--SourceReferenceFormatter.h2
7 files changed, 100 insertions, 28 deletions
diff --git a/AST.cpp b/AST.cpp
index 09f98dca..be64c698 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -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);
};
}