mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #134 from LianaHus/sol_error_types_refuctoring
Sol error types refuctoring
This commit is contained in:
commit
e1e6a0c531
@ -51,9 +51,9 @@ ASTAnnotation& ASTNode::annotation() const
|
||||
return *m_annotation;
|
||||
}
|
||||
|
||||
TypeError ASTNode::createTypeError(string const& _description) const
|
||||
Error ASTNode::createTypeError(string const& _description) const
|
||||
{
|
||||
return TypeError() << errinfo_sourceLocation(location()) << errinfo_comment(_description);
|
||||
return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
|
||||
}
|
||||
|
||||
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
|
||||
/// Creates a @ref TypeError exception and decorates it with the location of the node and
|
||||
/// the given description
|
||||
TypeError createTypeError(std::string const& _description) const;
|
||||
Error createTypeError(std::string const& _description) const;
|
||||
|
||||
///@todo make this const-safe by providing a different way to access the annotation
|
||||
virtual ASTAnnotation& annotation() const;
|
||||
@ -660,10 +660,14 @@ class MagicVariableDeclaration: public Declaration
|
||||
public:
|
||||
MagicVariableDeclaration(ASTString const& _name, std::shared_ptr<Type const> const& _type):
|
||||
Declaration(SourceLocation(), std::make_shared<ASTString>(_name)), m_type(_type) {}
|
||||
virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError()
|
||||
<< errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
|
||||
virtual void accept(ASTConstVisitor&) const override { BOOST_THROW_EXCEPTION(InternalCompilerError()
|
||||
<< errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
|
||||
virtual void accept(ASTVisitor&) override
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST."));
|
||||
}
|
||||
virtual void accept(ASTConstVisitor&) const override
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST."));
|
||||
}
|
||||
|
||||
virtual TypePointer type(ContractDefinition const*) const override { return m_type; }
|
||||
|
||||
|
@ -137,7 +137,7 @@ ModifierDefinition const& CompilerContext::functionModifier(string const& _name)
|
||||
if (modifier->name() == _name)
|
||||
return *modifier.get();
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError()
|
||||
<< errinfo_comment("Function modifier " + _name + " not found."));
|
||||
<< errinfo_comment("Function modifier " + _name + " not found."));
|
||||
}
|
||||
|
||||
unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declaration) const
|
||||
|
@ -97,30 +97,44 @@ void CompilerStack::setSource(string const& _sourceCode)
|
||||
|
||||
bool CompilerStack::parse()
|
||||
{
|
||||
//reset
|
||||
m_errors.clear();
|
||||
m_parseSuccessful = false;
|
||||
|
||||
for (auto& sourcePair: m_sources)
|
||||
{
|
||||
sourcePair.second.scanner->reset();
|
||||
sourcePair.second.ast = Parser().parse(sourcePair.second.scanner);
|
||||
sourcePair.second.ast = Parser(m_errors).parse(sourcePair.second.scanner); // todo check for errors
|
||||
}
|
||||
if (!Error::containsOnlyWarnings(m_errors))
|
||||
// errors while parsing. sould stop before type checking
|
||||
return false;
|
||||
|
||||
resolveImports();
|
||||
|
||||
m_globalContext = make_shared<GlobalContext>();
|
||||
NameAndTypeResolver resolver(m_globalContext->declarations());
|
||||
bool success = true;
|
||||
NameAndTypeResolver resolver(m_globalContext->declarations(), m_errors);
|
||||
for (Source const* source: m_sourceOrder)
|
||||
resolver.registerDeclarations(*source->ast);
|
||||
if (!resolver.registerDeclarations(*source->ast))
|
||||
return false;
|
||||
|
||||
for (Source const* source: m_sourceOrder)
|
||||
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
m_globalContext->setCurrentContract(*contract);
|
||||
resolver.updateDeclaration(*m_globalContext->currentThis());
|
||||
resolver.updateDeclaration(*m_globalContext->currentSuper());
|
||||
resolver.resolveNamesAndTypes(*contract);
|
||||
success = success && resolver.updateDeclaration(*m_globalContext->currentThis());
|
||||
success = success && resolver.updateDeclaration(*m_globalContext->currentSuper());
|
||||
success = success && resolver.resolveNamesAndTypes(*contract);
|
||||
m_contracts[contract->name()].contract = contract;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
m_parseSuccessful = false;
|
||||
return m_parseSuccessful;
|
||||
}
|
||||
InterfaceHandler interfaceHandler;
|
||||
bool typesFine = true;
|
||||
for (Source const* source: m_sourceOrder)
|
||||
@ -129,7 +143,7 @@ bool CompilerStack::parse()
|
||||
{
|
||||
m_globalContext->setCurrentContract(*contract);
|
||||
resolver.updateDeclaration(*m_globalContext->currentThis());
|
||||
TypeChecker typeChecker;
|
||||
TypeChecker typeChecker(m_errors);
|
||||
if (typeChecker.checkTypeRequirements(*contract))
|
||||
{
|
||||
contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract));
|
||||
@ -137,8 +151,8 @@ bool CompilerStack::parse()
|
||||
}
|
||||
else
|
||||
typesFine = false;
|
||||
|
||||
m_contracts[contract->name()].contract = contract;
|
||||
m_errors += typeChecker.errors();
|
||||
}
|
||||
m_parseSuccessful = typesFine;
|
||||
return m_parseSuccessful;
|
||||
@ -253,9 +267,8 @@ string const& CompilerStack::metadata(string const& _contractName, Documentation
|
||||
if (!m_parseSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||
|
||||
Contract const& currentContract = contract(_contractName);
|
||||
|
||||
std::unique_ptr<string const>* doc;
|
||||
Contract const& currentContract = contract(_contractName);
|
||||
|
||||
// checks wheather we already have the documentation
|
||||
switch (_type)
|
||||
@ -345,10 +358,11 @@ void CompilerStack::resolveImports()
|
||||
string const& id = import->identifier();
|
||||
if (!m_sources.count(id))
|
||||
BOOST_THROW_EXCEPTION(
|
||||
ParserError()
|
||||
<< errinfo_sourceLocation(import->location())
|
||||
<< errinfo_comment("Source not found.")
|
||||
Error(Error::Type::ParserError)
|
||||
<< errinfo_sourceLocation(import->location())
|
||||
<< errinfo_comment("Source not found.")
|
||||
);
|
||||
|
||||
toposort(&m_sources[id]);
|
||||
}
|
||||
sourceOrder.push_back(_source);
|
||||
@ -414,10 +428,12 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co
|
||||
auto it = m_sources.find(_sourceName);
|
||||
if (it == m_sources.end())
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Given source file not found."));
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
CompilerStack::Contract::Contract(): interfaceHandler(make_shared<InterfaceHandler>()) {}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <libdevcore/FixedHash.h>
|
||||
#include <libevmasm/SourceLocation.h>
|
||||
#include <libevmasm/LinkerObject.h>
|
||||
#include <libsolidity/Exceptions.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -164,7 +165,8 @@ public:
|
||||
std::tuple<int, int, int, int> positionFromSourceLocation(SourceLocation const& _sourceLocation) const;
|
||||
|
||||
/// @returns the list of errors that occured during parsing and type checking.
|
||||
std::vector<std::shared_ptr<Error const>> const& errors() const { return m_errors; }
|
||||
ErrorList const& errors() const { return m_errors; }
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
@ -212,7 +214,7 @@ private:
|
||||
std::shared_ptr<GlobalContext> m_globalContext;
|
||||
std::vector<Source const*> m_sourceOrder;
|
||||
std::map<std::string const, Contract> m_contracts;
|
||||
std::vector<std::shared_ptr<Error const>> m_errors;
|
||||
ErrorList m_errors;
|
||||
};
|
||||
|
||||
}
|
||||
|
52
libsolidity/Exceptions.cpp
Normal file
52
libsolidity/Exceptions.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @author Liana <liana@ethdev.com>
|
||||
* @date 2015
|
||||
* Solidity exception hierarchy.
|
||||
*/
|
||||
|
||||
#include <libsolidity/Exceptions.h>
|
||||
#include <libsolidity/Utils.h>
|
||||
|
||||
using namespace dev;
|
||||
using namespace dev::solidity;
|
||||
|
||||
Error::Error(Type _type): m_type(_type)
|
||||
{
|
||||
switch(m_type)
|
||||
{
|
||||
case Type::DeclarationError:
|
||||
m_typeName = "Declaration Error";
|
||||
break;
|
||||
case Type::DocstringParsingError:
|
||||
m_typeName = "Docstring Parsing Error";
|
||||
break;
|
||||
case Type::ParserError:
|
||||
m_typeName = "Parser Error";
|
||||
break;
|
||||
case Type::TypeError:
|
||||
m_typeName = "Type Error";
|
||||
break;
|
||||
case Type::Warning:
|
||||
m_typeName = "Warning";
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "");
|
||||
break;
|
||||
}
|
||||
}
|
@ -31,18 +31,55 @@ namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
struct Error: virtual Exception {};
|
||||
|
||||
struct ParserError: virtual Error {};
|
||||
struct TypeError: virtual Error {};
|
||||
struct DeclarationError: virtual Error {};
|
||||
struct DocstringParsingError: virtual Error {};
|
||||
struct Warning: virtual Error {};
|
||||
class Error;
|
||||
using ErrorList = std::vector<std::shared_ptr<Error const>>;
|
||||
|
||||
struct CompilerError: virtual Exception {};
|
||||
struct InternalCompilerError: virtual Exception {};
|
||||
struct FatalError: virtual Exception {};
|
||||
|
||||
class Error: virtual public Exception
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
DeclarationError,
|
||||
DocstringParsingError,
|
||||
ParserError,
|
||||
TypeError,
|
||||
Warning
|
||||
};
|
||||
|
||||
explicit Error(Type _type);
|
||||
|
||||
Type type() const { return m_type; }
|
||||
std::string const& typeName() const { return m_typeName; }
|
||||
|
||||
/// helper functions
|
||||
static Error const* containsErrorOfType(ErrorList const& _list, Error::Type _type)
|
||||
{
|
||||
for (auto e: _list)
|
||||
{
|
||||
if (e->type() == _type)
|
||||
return e.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static bool containsOnlyWarnings(ErrorList const& _list)
|
||||
{
|
||||
for (auto e: _list)
|
||||
{
|
||||
if (e->type() != Type::Warning)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
Type m_type;
|
||||
std::string m_typeName;
|
||||
};
|
||||
|
||||
|
||||
using errorSourceLocationInfo = std::pair<std::string, SourceLocation>;
|
||||
|
||||
class SecondarySourceLocation
|
||||
@ -56,6 +93,7 @@ public:
|
||||
std::vector<errorSourceLocationInfo> infos;
|
||||
};
|
||||
|
||||
|
||||
using errinfo_sourceLocation = boost::error_info<struct tag_sourceLocation, SourceLocation>;
|
||||
using errinfo_secondarySourceLocation = boost::error_info<struct tag_secondarySourceLocation, SecondarySourceLocation>;
|
||||
|
||||
|
@ -243,7 +243,7 @@ string InterfaceHandler::devDocumentation(ContractDefinition const& _contractDef
|
||||
if (find(paramNames.begin(), paramNames.end(), pair.first) == paramNames.end())
|
||||
// LTODO: mismatching parameter name, throw some form of warning and not just an exception
|
||||
BOOST_THROW_EXCEPTION(
|
||||
DocstringParsingError() <<
|
||||
Error(Error::Type::DocstringParsingError) <<
|
||||
errinfo_comment("documented parameter \"" + pair.first + "\" not found in the parameter list of the function.")
|
||||
);
|
||||
params[pair.first] = pair.second;
|
||||
@ -310,7 +310,7 @@ string::const_iterator InterfaceHandler::parseDocTagParam(
|
||||
// find param name
|
||||
auto currPos = find(_pos, _end, ' ');
|
||||
if (currPos == _end)
|
||||
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + string(_pos, _end)));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("End of param name not found" + string(_pos, _end)));
|
||||
|
||||
|
||||
auto paramName = string(_pos, currPos);
|
||||
@ -369,7 +369,7 @@ string::const_iterator InterfaceHandler::parseDocTag(
|
||||
return parseDocTagLine(_pos, _end, m_author, DocTagType::Author, false);
|
||||
else
|
||||
// LTODO: for now this else makes no sense but later comments will go to more language constructs
|
||||
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag is legal only for contracts"));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("@author tag is legal only for contracts"));
|
||||
}
|
||||
else if (_tag == "title")
|
||||
{
|
||||
@ -377,13 +377,13 @@ string::const_iterator InterfaceHandler::parseDocTag(
|
||||
return parseDocTagLine(_pos, _end, m_title, DocTagType::Title, false);
|
||||
else
|
||||
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag is legal only for contracts"));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("@title tag is legal only for contracts"));
|
||||
}
|
||||
else if (_tag == "param")
|
||||
return parseDocTagParam(_pos, _end);
|
||||
else
|
||||
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered"));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("Unknown tag " + _tag + " encountered"));
|
||||
}
|
||||
else
|
||||
return appendDocTag(_pos, _end, _owner);
|
||||
@ -410,13 +410,13 @@ string::const_iterator InterfaceHandler::appendDocTag(
|
||||
return parseDocTagLine(_pos, _end, m_author, DocTagType::Author, true);
|
||||
else
|
||||
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag in illegal comment"));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("@author tag in illegal comment"));
|
||||
case DocTagType::Title:
|
||||
if (_owner == CommentOwner::Contract)
|
||||
return parseDocTagLine(_pos, _end, m_title, DocTagType::Title, true);
|
||||
else
|
||||
// LTODO: Unknown tag, throw some form of warning and not just an exception
|
||||
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag in illegal comment"));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("@title tag in illegal comment"));
|
||||
case DocTagType::Param:
|
||||
return appendDocTagParam(_pos, _end);
|
||||
default:
|
||||
@ -451,7 +451,7 @@ void InterfaceHandler::parseDocString(string const& _string, CommentOwner _owner
|
||||
auto tagNameEndPos = firstSpaceOrNl(tagPos, end);
|
||||
if (tagNameEndPos == end)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
DocstringParsingError() <<
|
||||
Error(Error::Type::DocstringParsingError) <<
|
||||
errinfo_comment("End of tag " + string(tagPos, tagNameEndPos) + "not found"));
|
||||
|
||||
currPos = parseDocTag(tagNameEndPos + 1, end, string(tagPos + 1, tagNameEndPos), _owner);
|
||||
|
@ -33,88 +33,114 @@ namespace solidity
|
||||
{
|
||||
|
||||
NameAndTypeResolver::NameAndTypeResolver(
|
||||
vector<Declaration const*> const& _globals
|
||||
)
|
||||
vector<Declaration const*> const& _globals,
|
||||
ErrorList& _errors
|
||||
) :
|
||||
m_errors(_errors)
|
||||
{
|
||||
for (Declaration const* declaration: _globals)
|
||||
m_scopes[nullptr].registerDeclaration(*declaration);
|
||||
}
|
||||
|
||||
void NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
|
||||
bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
|
||||
{
|
||||
// The helper registers all declarations in m_scopes as a side-effect of its construction.
|
||||
DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit);
|
||||
try
|
||||
{
|
||||
DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit, m_errors);
|
||||
}
|
||||
catch (FatalError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
||||
bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
||||
{
|
||||
m_currentScope = &m_scopes[nullptr];
|
||||
|
||||
for (ASTPointer<InheritanceSpecifier> const& baseContract: _contract.baseContracts())
|
||||
ReferencesResolver resolver(*baseContract, *this, &_contract, nullptr);
|
||||
|
||||
m_currentScope = &m_scopes[&_contract];
|
||||
|
||||
linearizeBaseContracts(_contract);
|
||||
std::vector<ContractDefinition const*> properBases(
|
||||
++_contract.annotation().linearizedBaseContracts.begin(),
|
||||
_contract.annotation().linearizedBaseContracts.end()
|
||||
);
|
||||
|
||||
for (ContractDefinition const* base: properBases)
|
||||
importInheritedScope(*base);
|
||||
|
||||
for (ASTPointer<StructDefinition> const& structDef: _contract.definedStructs())
|
||||
ReferencesResolver resolver(*structDef, *this, &_contract, nullptr);
|
||||
for (ASTPointer<EnumDefinition> const& enumDef: _contract.definedEnums())
|
||||
ReferencesResolver resolver(*enumDef, *this, &_contract, nullptr);
|
||||
for (ASTPointer<VariableDeclaration> const& variable: _contract.stateVariables())
|
||||
ReferencesResolver resolver(*variable, *this, &_contract, nullptr);
|
||||
for (ASTPointer<EventDefinition> const& event: _contract.events())
|
||||
ReferencesResolver resolver(*event, *this, &_contract, nullptr);
|
||||
|
||||
// these can contain code, only resolve parameters for now
|
||||
for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers())
|
||||
try
|
||||
{
|
||||
m_currentScope = &m_scopes[modifier.get()];
|
||||
ReferencesResolver resolver(*modifier, *this, &_contract, nullptr);
|
||||
}
|
||||
for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions())
|
||||
{
|
||||
m_currentScope = &m_scopes[function.get()];
|
||||
ReferencesResolver referencesResolver(
|
||||
*function,
|
||||
*this,
|
||||
&_contract,
|
||||
function->returnParameterList().get()
|
||||
m_currentScope = &m_scopes[nullptr];
|
||||
|
||||
for (ASTPointer<InheritanceSpecifier> const& baseContract: _contract.baseContracts())
|
||||
ReferencesResolver resolver(*baseContract, *this, &_contract, nullptr);
|
||||
|
||||
m_currentScope = &m_scopes[&_contract];
|
||||
|
||||
linearizeBaseContracts(_contract);
|
||||
std::vector<ContractDefinition const*> properBases(
|
||||
++_contract.annotation().linearizedBaseContracts.begin(),
|
||||
_contract.annotation().linearizedBaseContracts.end()
|
||||
);
|
||||
}
|
||||
|
||||
m_currentScope = &m_scopes[&_contract];
|
||||
for (ContractDefinition const* base: properBases)
|
||||
importInheritedScope(*base);
|
||||
|
||||
// now resolve references inside the code
|
||||
for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers())
|
||||
{
|
||||
m_currentScope = &m_scopes[modifier.get()];
|
||||
ReferencesResolver resolver(*modifier, *this, &_contract, nullptr, true);
|
||||
for (ASTPointer<StructDefinition> const& structDef: _contract.definedStructs())
|
||||
ReferencesResolver resolver(*structDef, *this, &_contract, nullptr);
|
||||
for (ASTPointer<EnumDefinition> const& enumDef: _contract.definedEnums())
|
||||
ReferencesResolver resolver(*enumDef, *this, &_contract, nullptr);
|
||||
for (ASTPointer<VariableDeclaration> const& variable: _contract.stateVariables())
|
||||
ReferencesResolver resolver(*variable, *this, &_contract, nullptr);
|
||||
for (ASTPointer<EventDefinition> const& event: _contract.events())
|
||||
ReferencesResolver resolver(*event, *this, &_contract, nullptr);
|
||||
|
||||
// these can contain code, only resolve parameters for now
|
||||
for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers())
|
||||
{
|
||||
m_currentScope = &m_scopes[modifier.get()];
|
||||
ReferencesResolver resolver(*modifier, *this, &_contract, nullptr);
|
||||
}
|
||||
for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions())
|
||||
{
|
||||
m_currentScope = &m_scopes[function.get()];
|
||||
ReferencesResolver referencesResolver(
|
||||
*function,
|
||||
*this,
|
||||
&_contract,
|
||||
function->returnParameterList().get()
|
||||
);
|
||||
}
|
||||
|
||||
m_currentScope = &m_scopes[&_contract];
|
||||
|
||||
// now resolve references inside the code
|
||||
for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers())
|
||||
{
|
||||
m_currentScope = &m_scopes[modifier.get()];
|
||||
ReferencesResolver resolver(*modifier, *this, &_contract, nullptr, true);
|
||||
}
|
||||
for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions())
|
||||
{
|
||||
m_currentScope = &m_scopes[function.get()];
|
||||
ReferencesResolver referencesResolver(
|
||||
*function,
|
||||
*this,
|
||||
&_contract,
|
||||
function->returnParameterList().get(),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions())
|
||||
catch (FatalError const& _e)
|
||||
{
|
||||
m_currentScope = &m_scopes[function.get()];
|
||||
ReferencesResolver referencesResolver(
|
||||
*function,
|
||||
*this,
|
||||
&_contract,
|
||||
function->returnParameterList().get(),
|
||||
true
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
|
||||
bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
|
||||
{
|
||||
m_scopes[nullptr].registerDeclaration(_declaration, false, true);
|
||||
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
|
||||
try
|
||||
{
|
||||
m_scopes[nullptr].registerDeclaration(_declaration, false, true);
|
||||
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
|
||||
}
|
||||
catch(FatalError const& _error)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const
|
||||
@ -162,11 +188,8 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations(
|
||||
FunctionType functionType(functionDefinition);
|
||||
for (auto parameter: functionType.parameterTypes() + functionType.returnParameterTypes())
|
||||
if (!parameter)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
DeclarationError() <<
|
||||
errinfo_sourceLocation(_identifier.location()) <<
|
||||
errinfo_comment("Function type can not be used in this context")
|
||||
);
|
||||
reportFatalDeclarationError(_identifier.location(), "Function type can not be used in this context");
|
||||
|
||||
if (uniqueFunctions.end() == find_if(
|
||||
uniqueFunctions.begin(),
|
||||
uniqueFunctions.end(),
|
||||
@ -192,7 +215,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base)
|
||||
m_currentScope->registerDeclaration(*declaration);
|
||||
}
|
||||
|
||||
void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) const
|
||||
void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract)
|
||||
{
|
||||
// order in the lists is from derived to base
|
||||
// list of lists to linearize, the last element is the list of direct bases
|
||||
@ -202,19 +225,19 @@ void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract)
|
||||
Identifier const& baseName = baseSpecifier->name();
|
||||
auto base = dynamic_cast<ContractDefinition const*>(baseName.annotation().referencedDeclaration);
|
||||
if (!base)
|
||||
BOOST_THROW_EXCEPTION(baseName.createTypeError("Contract expected."));
|
||||
reportFatalTypeError(baseName.createTypeError("Contract expected."));
|
||||
// "push_front" has the effect that bases mentioned later can overwrite members of bases
|
||||
// mentioned earlier
|
||||
input.back().push_front(base);
|
||||
vector<ContractDefinition const*> const& basesBases = base->annotation().linearizedBaseContracts;
|
||||
if (basesBases.empty())
|
||||
BOOST_THROW_EXCEPTION(baseName.createTypeError("Definition of base has to precede definition of derived contract"));
|
||||
reportFatalTypeError(baseName.createTypeError("Definition of base has to precede definition of derived contract"));
|
||||
input.push_front(list<ContractDefinition const*>(basesBases.begin(), basesBases.end()));
|
||||
}
|
||||
input.back().push_front(&_contract);
|
||||
vector<ContractDefinition const*> result = cThreeMerge(input);
|
||||
if (result.empty())
|
||||
BOOST_THROW_EXCEPTION(_contract.createTypeError("Linearization of inheritance graph impossible"));
|
||||
reportFatalTypeError(_contract.createTypeError("Linearization of inheritance graph impossible"));
|
||||
_contract.annotation().linearizedBaseContracts = result;
|
||||
_contract.annotation().contractDependencies.insert(result.begin() + 1, result.end());
|
||||
}
|
||||
@ -270,9 +293,60 @@ vector<_T const*> NameAndTypeResolver::cThreeMerge(list<list<_T const*>>& _toMer
|
||||
return result;
|
||||
}
|
||||
|
||||
DeclarationRegistrationHelper::DeclarationRegistrationHelper(map<ASTNode const*, DeclarationContainer>& _scopes,
|
||||
ASTNode& _astRoot):
|
||||
m_scopes(_scopes), m_currentScope(nullptr)
|
||||
void NameAndTypeResolver::reportDeclarationError(
|
||||
SourceLocation _sourceLoction,
|
||||
string const& _description,
|
||||
SourceLocation _secondarySourceLocation,
|
||||
string const& _secondaryDescription
|
||||
)
|
||||
{
|
||||
auto err = make_shared<Error>(Error::Type::DeclarationError); // todo remove Error?
|
||||
*err <<
|
||||
errinfo_sourceLocation(_sourceLoction) <<
|
||||
errinfo_comment(_description) <<
|
||||
errinfo_secondarySourceLocation(
|
||||
SecondarySourceLocation().append(_secondaryDescription, _secondarySourceLocation)
|
||||
);
|
||||
|
||||
m_errors.push_back(err);
|
||||
}
|
||||
|
||||
void NameAndTypeResolver::reportDeclarationError(SourceLocation _sourceLocation, string const& _description)
|
||||
{
|
||||
auto err = make_shared<Error>(Error::Type::DeclarationError); // todo remove Error?
|
||||
*err << errinfo_sourceLocation(_sourceLocation) << errinfo_comment(_description);
|
||||
|
||||
m_errors.push_back(err);
|
||||
}
|
||||
|
||||
void NameAndTypeResolver::reportFatalDeclarationError(
|
||||
SourceLocation _sourceLocation,
|
||||
string const& _description
|
||||
)
|
||||
{
|
||||
reportDeclarationError(_sourceLocation, _description);
|
||||
BOOST_THROW_EXCEPTION(FatalError());
|
||||
}
|
||||
|
||||
void NameAndTypeResolver::reportTypeError(Error const& _e)
|
||||
{
|
||||
m_errors.push_back(make_shared<Error>(_e));
|
||||
}
|
||||
|
||||
void NameAndTypeResolver::reportFatalTypeError(Error const& _e)
|
||||
{
|
||||
reportTypeError(_e);
|
||||
BOOST_THROW_EXCEPTION(FatalError());
|
||||
}
|
||||
|
||||
DeclarationRegistrationHelper::DeclarationRegistrationHelper(
|
||||
map<ASTNode const*, DeclarationContainer>& _scopes,
|
||||
ASTNode& _astRoot,
|
||||
ErrorList& _errors
|
||||
):
|
||||
m_scopes(_scopes),
|
||||
m_currentScope(nullptr),
|
||||
m_errors(_errors)
|
||||
{
|
||||
_astRoot.accept(*this);
|
||||
}
|
||||
@ -407,13 +481,11 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
|
||||
secondDeclarationLocation = _declaration.location();
|
||||
}
|
||||
|
||||
BOOST_THROW_EXCEPTION(
|
||||
DeclarationError() <<
|
||||
errinfo_sourceLocation(secondDeclarationLocation) <<
|
||||
errinfo_comment("Identifier already declared.") <<
|
||||
errinfo_secondarySourceLocation(
|
||||
SecondarySourceLocation().append("The previous declaration is here:", firstDeclarationLocation)
|
||||
)
|
||||
declarationError(
|
||||
secondDeclarationLocation,
|
||||
"Identifier already declared.",
|
||||
firstDeclarationLocation,
|
||||
"The previous declaration is here:"
|
||||
);
|
||||
}
|
||||
|
||||
@ -438,5 +510,40 @@ string DeclarationRegistrationHelper::currentCanonicalName() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DeclarationRegistrationHelper::declarationError(
|
||||
SourceLocation _sourceLocation,
|
||||
string const& _description,
|
||||
SourceLocation _secondarySourceLocation,
|
||||
string const& _secondaryDescription
|
||||
)
|
||||
{
|
||||
auto err = make_shared<Error>(Error::Type::DeclarationError);
|
||||
*err <<
|
||||
errinfo_sourceLocation(_sourceLocation) <<
|
||||
errinfo_comment(_description) <<
|
||||
errinfo_secondarySourceLocation(
|
||||
SecondarySourceLocation().append(_secondaryDescription, _secondarySourceLocation)
|
||||
);
|
||||
|
||||
m_errors.push_back(err);
|
||||
}
|
||||
|
||||
void DeclarationRegistrationHelper::declarationError(SourceLocation _sourceLocation, string const& _description)
|
||||
{
|
||||
auto err = make_shared<Error>(Error::Type::DeclarationError);
|
||||
*err << errinfo_sourceLocation(_sourceLocation) << errinfo_comment(_description);
|
||||
|
||||
m_errors.push_back(err);
|
||||
}
|
||||
|
||||
void DeclarationRegistrationHelper::fatalDeclarationError(
|
||||
SourceLocation _sourceLocation,
|
||||
string const& _description
|
||||
)
|
||||
{
|
||||
declarationError(_sourceLocation, _description);
|
||||
BOOST_THROW_EXCEPTION(FatalError());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -42,14 +42,17 @@ namespace solidity
|
||||
class NameAndTypeResolver: private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
NameAndTypeResolver(std::vector<Declaration const*> const& _globals);
|
||||
NameAndTypeResolver(std::vector<Declaration const*> const& _globals, ErrorList& _errors);
|
||||
/// Registers all declarations found in the source unit.
|
||||
void registerDeclarations(SourceUnit& _sourceUnit);
|
||||
/// @returns false in case of error.
|
||||
bool registerDeclarations(SourceUnit& _sourceUnit);
|
||||
/// Resolves all names and types referenced from the given contract.
|
||||
void resolveNamesAndTypes(ContractDefinition& _contract);
|
||||
/// @returns false in case of error.
|
||||
bool resolveNamesAndTypes(ContractDefinition& _contract);
|
||||
/// Updates the given global declaration (used for "this"). Not to be used with declarations
|
||||
/// that create their own scope.
|
||||
void updateDeclaration(Declaration const& _declaration);
|
||||
/// @returns false in case of error.
|
||||
bool updateDeclaration(Declaration const& _declaration);
|
||||
|
||||
/// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted,
|
||||
/// the global scope is used (i.e. the one containing only the contract).
|
||||
@ -66,7 +69,7 @@ public:
|
||||
Declaration const* pathFromCurrentScope(std::vector<ASTString> const& _path, bool _recursive = true) const;
|
||||
|
||||
/// returns the vector of declarations without repetitions
|
||||
static std::vector<Declaration const*> cleanedDeclarations(
|
||||
std::vector<Declaration const*> cleanedDeclarations(
|
||||
Identifier const& _identifier,
|
||||
std::vector<Declaration const*> const& _declarations
|
||||
);
|
||||
@ -78,8 +81,8 @@ private:
|
||||
/// into the current scope if they are not present already.
|
||||
void importInheritedScope(ContractDefinition const& _base);
|
||||
|
||||
/// Computes "C3-Linearization" of base contracts and stores it inside the contract.
|
||||
void linearizeBaseContracts(ContractDefinition& _contract) const;
|
||||
/// Computes "C3-Linearization" of base contracts and stores it inside the contract. Reports errors if any
|
||||
void linearizeBaseContracts(ContractDefinition& _contract);
|
||||
/// Computes the C3-merge of the given list of lists of bases.
|
||||
/// @returns the linearized vector or an empty vector if linearization is not possible.
|
||||
template <class _T>
|
||||
@ -90,7 +93,25 @@ private:
|
||||
/// not contain code.
|
||||
std::map<ASTNode const*, DeclarationContainer> m_scopes;
|
||||
|
||||
// creates the Declaration error and adds it in the errors list
|
||||
void reportDeclarationError(
|
||||
SourceLocation _sourceLoction,
|
||||
std::string const& _description,
|
||||
SourceLocation _secondarySourceLocation,
|
||||
std::string const& _secondaryDescription
|
||||
);
|
||||
// creates the Declaration error and adds it in the errors list
|
||||
void reportDeclarationError(SourceLocation _sourceLocation, std::string const& _description);
|
||||
// creates the Declaration error and adds it in the errors list and throws FatalError
|
||||
void reportFatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description);
|
||||
|
||||
// creates the Declaration error and adds it in the errors list
|
||||
void reportTypeError(Error const& _e);
|
||||
// creates the Declaration error and adds it in the errors list and throws FatalError
|
||||
void reportFatalTypeError(Error const& _e);
|
||||
|
||||
DeclarationContainer* m_currentScope = nullptr;
|
||||
ErrorList& m_errors;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -100,7 +121,7 @@ private:
|
||||
class DeclarationRegistrationHelper: private ASTVisitor
|
||||
{
|
||||
public:
|
||||
DeclarationRegistrationHelper(std::map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot);
|
||||
DeclarationRegistrationHelper(std::map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot, ErrorList& _errors);
|
||||
|
||||
private:
|
||||
bool visit(ContractDefinition& _contract) override;
|
||||
@ -125,10 +146,23 @@ private:
|
||||
|
||||
/// @returns the canonical name of the current scope.
|
||||
std::string currentCanonicalName() const;
|
||||
// creates the Declaration error and adds it in the errors list
|
||||
void declarationError(
|
||||
SourceLocation _sourceLocation,
|
||||
std::string const& _description,
|
||||
SourceLocation _secondarySourceLocation,
|
||||
std::string const& _secondaryDescription
|
||||
);
|
||||
|
||||
// creates the Declaration error and adds it in the errors list
|
||||
void declarationError(SourceLocation _sourceLocation, std::string const& _description);
|
||||
// creates the Declaration error and adds it in the errors list and throws FatalError
|
||||
void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description);
|
||||
|
||||
std::map<ASTNode const*, DeclarationContainer>& m_scopes;
|
||||
Declaration const* m_currentScope;
|
||||
VariableScope* m_currentFunction;
|
||||
ErrorList& m_errors;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -66,25 +66,36 @@ private:
|
||||
|
||||
ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
|
||||
{
|
||||
m_scanner = _scanner;
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
vector<ASTPointer<ASTNode>> nodes;
|
||||
while (m_scanner->currentToken() != Token::EOS)
|
||||
try
|
||||
{
|
||||
switch (auto token = m_scanner->currentToken())
|
||||
m_scanner = _scanner;
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
vector<ASTPointer<ASTNode>> nodes;
|
||||
while (m_scanner->currentToken() != Token::EOS)
|
||||
{
|
||||
case Token::Import:
|
||||
nodes.push_back(parseImportDirective());
|
||||
break;
|
||||
case Token::Contract:
|
||||
case Token::Library:
|
||||
nodes.push_back(parseContractDefinition(token == Token::Library));
|
||||
break;
|
||||
default:
|
||||
BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition.")));
|
||||
switch (auto token = m_scanner->currentToken())
|
||||
{
|
||||
case Token::Import:
|
||||
nodes.push_back(parseImportDirective());
|
||||
break;
|
||||
case Token::Contract:
|
||||
case Token::Library:
|
||||
nodes.push_back(parseContractDefinition(token == Token::Library));
|
||||
break;
|
||||
default:
|
||||
fatalParserError(std::string("Expected import directive or contract definition."));
|
||||
}
|
||||
}
|
||||
return nodeFactory.createNode<SourceUnit>(nodes);
|
||||
}
|
||||
catch(FatalError const& _error)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
catch(Exception const& _e)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return nodeFactory.createNode<SourceUnit>(nodes);
|
||||
}
|
||||
|
||||
std::shared_ptr<const string> const& Parser::sourceName() const
|
||||
@ -107,7 +118,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
expectToken(Token::Import);
|
||||
if (m_scanner->currentToken() != Token::StringLiteral)
|
||||
BOOST_THROW_EXCEPTION(createParserError("Expected string literal (URL)."));
|
||||
fatalParserError(std::string("Expected string literal (URL)."));
|
||||
ASTPointer<ASTString> url = getLiteralAndAdvance();
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::Semicolon);
|
||||
@ -165,7 +176,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary)
|
||||
else if (currentTokenValue == Token::Event)
|
||||
events.push_back(parseEventDefinition());
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(createParserError("Function, variable, struct or modifier declaration expected."));
|
||||
fatalParserError(std::string("Function, variable, struct or modifier declaration expected."));
|
||||
}
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::RBrace);
|
||||
@ -249,7 +260,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const*
|
||||
else if (Token::isVisibilitySpecifier(token))
|
||||
{
|
||||
if (visibility != Declaration::Visibility::Default)
|
||||
BOOST_THROW_EXCEPTION(createParserError("Multiple visibility specifiers."));
|
||||
fatalParserError(std::string("Multiple visibility specifiers."));
|
||||
visibility = parseVisibilitySpecifier(token);
|
||||
}
|
||||
else
|
||||
@ -326,7 +337,7 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition()
|
||||
break;
|
||||
expectToken(Token::Comma);
|
||||
if (m_scanner->currentToken() != Token::Identifier)
|
||||
BOOST_THROW_EXCEPTION(createParserError("Expected Identifier after ','"));
|
||||
fatalParserError(std::string("Expected Identifier after ','"));
|
||||
}
|
||||
|
||||
nodeFactory.markEndPosition();
|
||||
@ -362,7 +373,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token))
|
||||
{
|
||||
if (visibility != Declaration::Visibility::Default)
|
||||
BOOST_THROW_EXCEPTION(createParserError("Visibility already specified."));
|
||||
fatalParserError(std::string("Visibility already specified."));
|
||||
visibility = parseVisibilitySpecifier(token);
|
||||
}
|
||||
else
|
||||
@ -374,9 +385,9 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
else if (_options.allowLocationSpecifier && Token::isLocationSpecifier(token))
|
||||
{
|
||||
if (location != VariableDeclaration::Location::Default)
|
||||
BOOST_THROW_EXCEPTION(createParserError("Location already specified."));
|
||||
fatalParserError(std::string("Location already specified."));
|
||||
if (!type)
|
||||
BOOST_THROW_EXCEPTION(createParserError("Location specifier needs explicit type name."));
|
||||
fatalParserError(std::string("Location specifier needs explicit type name."));
|
||||
location = (
|
||||
token == Token::Memory ?
|
||||
VariableDeclaration::Location::Memory :
|
||||
@ -513,7 +524,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
||||
else if (token == Token::Var)
|
||||
{
|
||||
if (!_allowVar)
|
||||
BOOST_THROW_EXCEPTION(createParserError("Expected explicit type name."));
|
||||
fatalParserError(std::string("Expected explicit type name."));
|
||||
m_scanner->next();
|
||||
}
|
||||
else if (token == Token::Mapping)
|
||||
@ -532,7 +543,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
||||
type = nodeFactory.createNode<UserDefinedTypeName>(identifierPath);
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(createParserError("Expected type name"));
|
||||
fatalParserError(std::string("Expected type name"));
|
||||
|
||||
if (type)
|
||||
// Parse "[...]" postfixes for arrays.
|
||||
@ -555,7 +566,7 @@ ASTPointer<Mapping> Parser::parseMapping()
|
||||
expectToken(Token::Mapping);
|
||||
expectToken(Token::LParen);
|
||||
if (!Token::isElementaryTypeName(m_scanner->currentToken()))
|
||||
BOOST_THROW_EXCEPTION(createParserError("Expected elementary type name for mapping key type"));
|
||||
fatalParserError(std::string("Expected elementary type name for mapping key type"));
|
||||
ASTPointer<ElementaryTypeName> keyType;
|
||||
keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->currentToken());
|
||||
m_scanner->next();
|
||||
@ -1011,7 +1022,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
|
||||
m_scanner->next();
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(createParserError("Expected primary expression."));
|
||||
fatalParserError(std::string("Expected primary expression."));
|
||||
break;
|
||||
}
|
||||
return expression;
|
||||
@ -1122,7 +1133,7 @@ ASTPointer<Expression> Parser::expressionFromIndexAccessStructure(
|
||||
void Parser::expectToken(Token::Value _value)
|
||||
{
|
||||
if (m_scanner->currentToken() != _value)
|
||||
BOOST_THROW_EXCEPTION(createParserError(string("Expected token ") + string(Token::name(_value))));
|
||||
fatalParserError(std::string(string("Expected token ") + string(Token::name(_value))));
|
||||
m_scanner->next();
|
||||
}
|
||||
|
||||
@ -1130,7 +1141,7 @@ Token::Value Parser::expectAssignmentOperator()
|
||||
{
|
||||
Token::Value op = m_scanner->currentToken();
|
||||
if (!Token::isAssignmentOp(op))
|
||||
BOOST_THROW_EXCEPTION(createParserError("Expected assignment operator"));
|
||||
fatalParserError(std::string("Expected assignment operator"));
|
||||
m_scanner->next();
|
||||
return op;
|
||||
}
|
||||
@ -1138,7 +1149,7 @@ Token::Value Parser::expectAssignmentOperator()
|
||||
ASTPointer<ASTString> Parser::expectIdentifierToken()
|
||||
{
|
||||
if (m_scanner->currentToken() != Token::Identifier)
|
||||
BOOST_THROW_EXCEPTION(createParserError("Expected identifier"));
|
||||
fatalParserError(std::string("Expected identifier"));
|
||||
return getLiteralAndAdvance();
|
||||
}
|
||||
|
||||
@ -1156,13 +1167,21 @@ ASTPointer<ParameterList> Parser::createEmptyParameterList()
|
||||
return nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>());
|
||||
}
|
||||
|
||||
ParserError Parser::createParserError(string const& _description) const
|
||||
void Parser::parserError(string const& _description)
|
||||
{
|
||||
return ParserError() <<
|
||||
auto err = make_shared<Error>(Error::Type::ParserError);
|
||||
*err <<
|
||||
errinfo_sourceLocation(SourceLocation(position(), position(), sourceName())) <<
|
||||
errinfo_comment(_description);
|
||||
|
||||
m_errors.push_back(err);
|
||||
}
|
||||
|
||||
void Parser::fatalParserError(string const& _description)
|
||||
{
|
||||
parserError(_description);
|
||||
BOOST_THROW_EXCEPTION(FatalError());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class Scanner;
|
||||
class Parser
|
||||
{
|
||||
public:
|
||||
Parser() {}
|
||||
Parser(ErrorList& errors): m_errors(errors){};
|
||||
|
||||
ASTPointer<SourceUnit> parse(std::shared_ptr<Scanner> const& _scanner);
|
||||
std::shared_ptr<std::string const> const& sourceName() const;
|
||||
@ -145,13 +145,19 @@ private:
|
||||
/// Creates an empty ParameterList at the current location (used if parameters can be omitted).
|
||||
ASTPointer<ParameterList> createEmptyParameterList();
|
||||
|
||||
/// Creates a @ref ParserError exception and annotates it with the current position and the
|
||||
/// Creates a @ref ParserError and annotates it with the current position and the
|
||||
/// given @a _description.
|
||||
ParserError createParserError(std::string const& _description) const;
|
||||
void parserError(std::string const& _description);
|
||||
|
||||
/// Creates a @ref ParserError and annotates it with the current position and the
|
||||
/// given @a _description. Throws the FatalError.
|
||||
void fatalParserError(std::string const& _description);
|
||||
|
||||
std::shared_ptr<Scanner> m_scanner;
|
||||
/// Flag that signifies whether '_' is parsed as a PlaceholderStatement or a regular identifier.
|
||||
bool m_insideModifier = false;
|
||||
/// The reference to the list of errors and warning to add errors/warnings during parsing
|
||||
ErrorList& m_errors;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName)
|
||||
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
|
||||
if (!declaration)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
DeclarationError() <<
|
||||
Error(Error::Type::DeclarationError) <<
|
||||
errinfo_sourceLocation(_typeName.location()) <<
|
||||
errinfo_comment("Identifier not found or not unique.")
|
||||
);
|
||||
@ -70,7 +70,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
|
||||
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name());
|
||||
if (declarations.empty())
|
||||
BOOST_THROW_EXCEPTION(
|
||||
DeclarationError() <<
|
||||
Error(Error::Type::DeclarationError) <<
|
||||
errinfo_sourceLocation(_identifier.location()) <<
|
||||
errinfo_comment("Undeclared identifier.")
|
||||
);
|
||||
|
@ -43,14 +43,7 @@ bool TypeChecker::checkTypeRequirements(const ContractDefinition& _contract)
|
||||
if (m_errors.empty())
|
||||
throw; // Something is weird here, rather throw again.
|
||||
}
|
||||
bool success = true;
|
||||
for (auto const& it: m_errors)
|
||||
if (!dynamic_cast<Warning const*>(it.get()))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
return success;
|
||||
return Error::containsOnlyWarnings(m_errors);
|
||||
}
|
||||
|
||||
TypePointer const& TypeChecker::type(Expression const& _expression) const
|
||||
@ -87,7 +80,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||
{
|
||||
if (fallbackFunction)
|
||||
{
|
||||
auto err = make_shared<DeclarationError>();
|
||||
auto err = make_shared<Error>(Error::Type::DeclarationError);
|
||||
*err << errinfo_comment("Only one fallback function is allowed.");
|
||||
m_errors.push_back(err);
|
||||
}
|
||||
@ -143,7 +136,7 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con
|
||||
for (; it != functions[_contract.name()].end(); ++it)
|
||||
ssl.append("Another declaration is here:", (*it)->location());
|
||||
|
||||
auto err = make_shared<DeclarationError>();
|
||||
auto err = make_shared<Error>(Error(Error::Type::DeclarationError));
|
||||
*err <<
|
||||
errinfo_sourceLocation(functions[_contract.name()].front()->location()) <<
|
||||
errinfo_comment("More than one constructor defined.") <<
|
||||
@ -157,7 +150,7 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con
|
||||
for (size_t j = i + 1; j < overloads.size(); ++j)
|
||||
if (FunctionType(*overloads[i]).hasEqualArgumentTypes(FunctionType(*overloads[j])))
|
||||
{
|
||||
auto err = make_shared<DeclarationError>();
|
||||
auto err = make_shared<Error>(Error(Error::Type::DeclarationError));
|
||||
*err <<
|
||||
errinfo_sourceLocation(overloads[j]->location()) <<
|
||||
errinfo_comment("Function with same name and arguments defined twice.") <<
|
||||
@ -601,7 +594,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
{
|
||||
if (ref->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
auto err = make_shared<Warning>();
|
||||
auto err = make_shared<Error>(Error::Type::Warning);
|
||||
*err <<
|
||||
errinfo_sourceLocation(varDecl.location()) <<
|
||||
errinfo_comment("Uninitialized storage pointer. Did you mean '<type> memory " + varDecl.name() + "'?");
|
||||
@ -1251,7 +1244,7 @@ void TypeChecker::requireLValue(Expression const& _expression)
|
||||
|
||||
void TypeChecker::typeError(ASTNode const& _node, string const& _description)
|
||||
{
|
||||
auto err = make_shared<TypeError>();
|
||||
auto err = make_shared<Error>(Error::Type::TypeError);
|
||||
*err <<
|
||||
errinfo_sourceLocation(_node.location()) <<
|
||||
errinfo_comment(_description);
|
||||
|
@ -42,26 +42,26 @@ namespace solidity
|
||||
class TypeChecker: private ASTConstVisitor
|
||||
{
|
||||
public:
|
||||
/// @param _errors the reference to the list of errors and warnings to add them found during type checking.
|
||||
TypeChecker(ErrorList& _errors): m_errors(_errors) {}
|
||||
|
||||
/// Performs type checking on the given contract and all of its sub-nodes.
|
||||
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
|
||||
bool checkTypeRequirements(ContractDefinition const& _contract);
|
||||
|
||||
/// @returns the list of errors and warnings found during type checking.
|
||||
std::vector<std::shared_ptr<Error const>> const& errors() const { return m_errors; }
|
||||
|
||||
/// @returns the type of an expression and asserts that it is present.
|
||||
TypePointer const& type(Expression const& _expression) const;
|
||||
/// @returns the type of the given variable and throws if the type is not present
|
||||
/// (this can happen for variables with non-explicit types before their types are resolved)
|
||||
TypePointer const& type(VariableDeclaration const& _variable) const;
|
||||
|
||||
private:
|
||||
/// Adds a new error to the list of errors.
|
||||
void typeError(ASTNode const& _node, std::string const& _description);
|
||||
|
||||
/// Adds a new error to the list of errors and throws to abort type checking.
|
||||
void fatalTypeError(ASTNode const& _node, std::string const& _description);
|
||||
|
||||
private:
|
||||
virtual bool visit(ContractDefinition const& _contract) override;
|
||||
/// Checks that two functions defined in this contract with the same name have different
|
||||
/// arguments and that there is at most one constructor.
|
||||
@ -114,7 +114,7 @@ private:
|
||||
/// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
|
||||
void requireLValue(Expression const& _expression);
|
||||
|
||||
std::vector<std::shared_ptr<Error const>> m_errors;
|
||||
ErrorList& m_errors;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ void StorageOffsets::computeOffsets(TypePointers const& _types)
|
||||
byteOffset = 0;
|
||||
}
|
||||
if (slotOffset >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Object too large for storage."));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Object too large for storage."));
|
||||
offsets[i] = make_pair(u256(slotOffset), byteOffset);
|
||||
solAssert(type->storageSize() >= 1, "Invalid storage size.");
|
||||
if (type->storageSize() == 1 && byteOffset + type->storageBytes() <= 32)
|
||||
@ -64,7 +64,7 @@ void StorageOffsets::computeOffsets(TypePointers const& _types)
|
||||
if (byteOffset > 0)
|
||||
++slotOffset;
|
||||
if (slotOffset >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Object too large for storage."));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Object too large for storage."));
|
||||
m_storageSize = u256(slotOffset);
|
||||
swap(m_offsets, offsets);
|
||||
}
|
||||
@ -805,7 +805,7 @@ u256 ArrayType::storageSize() const
|
||||
else
|
||||
size = bigint(length()) * baseType()->storageSize();
|
||||
if (size >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Array too large for storage."));
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Array too large for storage."));
|
||||
return max<u256>(1, u256(size));
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,14 @@
|
||||
#include <libdevcore/Assertions.h>
|
||||
#include <libsolidity/Exceptions.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
struct InternalCompilerError;
|
||||
}
|
||||
}
|
||||
|
||||
/// Assertion that throws an InternalCompilerError containing the given description if it is not met.
|
||||
#define solAssert(CONDITION, DESCRIPTION) \
|
||||
assertThrow(CONDITION, ::dev::solidity::InternalCompilerError, DESCRIPTION)
|
||||
|
@ -496,27 +496,12 @@ bool CommandLineInterface::processInput()
|
||||
SourceReferenceFormatter::printExceptionInformation(
|
||||
cerr,
|
||||
*error,
|
||||
(dynamic_pointer_cast<Warning const>(error)) ? "Warning" : "Error", *m_compiler
|
||||
(error->type() == Error::Type::Warning) ? "Warning" : "Error", *m_compiler
|
||||
);
|
||||
if (!successful)
|
||||
return false;
|
||||
m_compiler->link(m_libraries);
|
||||
}
|
||||
catch (ParserError const& _exception)
|
||||
{
|
||||
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Parser error", *m_compiler);
|
||||
return false;
|
||||
}
|
||||
catch (DeclarationError const& _exception)
|
||||
{
|
||||
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Declaration error", *m_compiler);
|
||||
return false;
|
||||
}
|
||||
catch (TypeError const& _exception)
|
||||
{
|
||||
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Type error", *m_compiler);
|
||||
return false;
|
||||
}
|
||||
catch (CompilerError const& _exception)
|
||||
{
|
||||
SourceReferenceFormatter::printExceptionInformation(cerr, _exception, "Compiler error", *m_compiler);
|
||||
@ -528,9 +513,13 @@ bool CommandLineInterface::processInput()
|
||||
<< boost::diagnostic_information(_exception);
|
||||
return false;
|
||||
}
|
||||
catch (DocstringParsingError const& _exception)
|
||||
catch (Error const& _error)
|
||||
{
|
||||
cerr << "Documentation parsing error: " << *boost::get_error_info<errinfo_comment>(_exception) << endl;
|
||||
if (_error.type() == Error::Type::DocstringParsingError)
|
||||
cerr << "Documentation parsing error: " << *boost::get_error_info<errinfo_comment>(_error) << endl;
|
||||
else
|
||||
SourceReferenceFormatter::printExceptionInformation(cerr, _error, _error.typeName(), *m_compiler);
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception const& _exception)
|
||||
|
@ -127,24 +127,19 @@ string compile(string _input, bool _optimize)
|
||||
{
|
||||
bool succ = compiler.compile(_input, _optimize);
|
||||
for (auto const& error: compiler.errors())
|
||||
{
|
||||
auto err = dynamic_pointer_cast<Error const>(error);
|
||||
errors.append(formatError(
|
||||
*error,
|
||||
(dynamic_pointer_cast<Warning const>(error)) ? "Warning" : "Error",
|
||||
(err->type() == Error::Type::Warning) ? "Warning" : "Error",
|
||||
compiler
|
||||
));
|
||||
}
|
||||
success = succ; // keep success false on exception
|
||||
}
|
||||
catch (ParserError const& exception)
|
||||
catch (Error const& error)
|
||||
{
|
||||
errors.append(formatError(exception, "Parser error", compiler));
|
||||
}
|
||||
catch (DeclarationError const& exception)
|
||||
{
|
||||
errors.append(formatError(exception, "Declaration error", compiler));
|
||||
}
|
||||
catch (TypeError const& exception)
|
||||
{
|
||||
errors.append(formatError(exception, "Type error", compiler));
|
||||
errors.append(formatError(error, error.typeName(), compiler));
|
||||
}
|
||||
catch (CompilerError const& exception)
|
||||
{
|
||||
@ -154,10 +149,6 @@ string compile(string _input, bool _optimize)
|
||||
{
|
||||
errors.append(formatError(exception, "Internal compiler error", compiler));
|
||||
}
|
||||
catch (DocstringParsingError const& exception)
|
||||
{
|
||||
errors.append(formatError(exception, "Documentation parsing error", compiler));
|
||||
}
|
||||
catch (Exception const& exception)
|
||||
{
|
||||
errors.append("Exception during compilation: " + boost::diagnostic_information(exception));
|
||||
|
@ -48,21 +48,29 @@ namespace
|
||||
|
||||
eth::AssemblyItems compileContract(const string& _sourceCode)
|
||||
{
|
||||
Parser parser;
|
||||
ErrorList errors;
|
||||
Parser parser(errors);
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
|
||||
NameAndTypeResolver resolver({});
|
||||
BOOST_CHECK(!!sourceUnit);
|
||||
|
||||
NameAndTypeResolver resolver({}, errors);
|
||||
solAssert(Error::containsOnlyWarnings(errors), "");
|
||||
resolver.registerDeclarations(*sourceUnit);
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
|
||||
if (!Error::containsOnlyWarnings(errors))
|
||||
return AssemblyItems();
|
||||
}
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
TypeChecker checker;
|
||||
TypeChecker checker(errors);
|
||||
BOOST_REQUIRE_NO_THROW(checker.checkTypeRequirements(*contract));
|
||||
if (!Error::containsOnlyWarnings(errors))
|
||||
return AssemblyItems();
|
||||
}
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
|
@ -45,9 +45,10 @@ public:
|
||||
m_reader.parse(generatedInterfaceString, generatedInterface);
|
||||
Json::Value expectedInterface;
|
||||
m_reader.parse(_expectedInterfaceString, expectedInterface);
|
||||
BOOST_CHECK_MESSAGE(expectedInterface == generatedInterface,
|
||||
"Expected:\n" << expectedInterface.toStyledString() <<
|
||||
"\n but got:\n" << generatedInterface.toStyledString());
|
||||
BOOST_CHECK_MESSAGE(
|
||||
expectedInterface == generatedInterface,
|
||||
"Expected:\n" << expectedInterface.toStyledString() << "\n but got:\n" << generatedInterface.toStyledString()
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -4705,7 +4705,7 @@ BOOST_AUTO_TEST_CASE(dev_title_at_function_error)
|
||||
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
|
||||
"}\n";
|
||||
|
||||
compileRequireThrow<DocstringParsingError>(sourceCode);
|
||||
compileRequireError(sourceCode, Error::Type::DocstringParsingError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_documenting_nonexistant_param)
|
||||
@ -4717,7 +4717,7 @@ BOOST_AUTO_TEST_CASE(dev_documenting_nonexistant_param)
|
||||
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
|
||||
"}\n";
|
||||
|
||||
compileRequireThrow<DocstringParsingError>(sourceCode);
|
||||
compileRequireError(sourceCode, Error::Type::DocstringParsingError);
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,15 +85,20 @@ Declaration const& resolveDeclaration(
|
||||
return *declaration;
|
||||
}
|
||||
|
||||
bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _functions = {},
|
||||
vector<vector<string>> _localVariables = {},
|
||||
vector<shared_ptr<MagicVariableDeclaration const>> _globalDeclarations = {})
|
||||
bytes compileFirstExpression(
|
||||
const string& _sourceCode,
|
||||
vector<vector<string>> _functions = {},
|
||||
vector<vector<string>> _localVariables = {},
|
||||
vector<shared_ptr<MagicVariableDeclaration const>> _globalDeclarations = {}
|
||||
)
|
||||
{
|
||||
Parser parser;
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
try
|
||||
{
|
||||
sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode)));
|
||||
ErrorList errors;
|
||||
sourceUnit = Parser(errors).parse(make_shared<Scanner>(CharStream(_sourceCode)));
|
||||
if (!sourceUnit)
|
||||
return bytes();
|
||||
}
|
||||
catch(boost::exception const& _e)
|
||||
{
|
||||
@ -105,7 +110,9 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
|
||||
declarations.reserve(_globalDeclarations.size() + 1);
|
||||
for (ASTPointer<Declaration const> const& variable: _globalDeclarations)
|
||||
declarations.push_back(variable.get());
|
||||
NameAndTypeResolver resolver(declarations);
|
||||
|
||||
ErrorList errors;
|
||||
NameAndTypeResolver resolver(declarations, errors);
|
||||
resolver.registerDeclarations(*sourceUnit);
|
||||
|
||||
vector<ContractDefinition const*> inheritanceHierarchy;
|
||||
@ -118,7 +125,7 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
TypeChecker typeChecker;
|
||||
TypeChecker typeChecker(errors);
|
||||
BOOST_REQUIRE(typeChecker.checkTypeRequirements(*contract));
|
||||
}
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,10 +39,11 @@ namespace test
|
||||
|
||||
namespace
|
||||
{
|
||||
ASTPointer<ContractDefinition> parseText(std::string const& _source)
|
||||
ASTPointer<ContractDefinition> parseText(std::string const& _source, ErrorList& _errors)
|
||||
{
|
||||
Parser parser;
|
||||
ASTPointer<SourceUnit> sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
|
||||
ASTPointer<SourceUnit> sourceUnit = Parser(_errors).parse(std::make_shared<Scanner>(CharStream(_source)));
|
||||
if (!sourceUnit)
|
||||
return ASTPointer<ContractDefinition>();
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ASTPointer<ContractDefinition> contract = dynamic_pointer_cast<ContractDefinition>(node))
|
||||
return contract;
|
||||
@ -50,8 +51,31 @@ ASTPointer<ContractDefinition> parseText(std::string const& _source)
|
||||
return ASTPointer<ContractDefinition>();
|
||||
}
|
||||
|
||||
static void checkFunctionNatspec(ASTPointer<FunctionDefinition> _function,
|
||||
std::string const& _expectedDoc)
|
||||
bool successParse(std::string const& _source)
|
||||
{
|
||||
ErrorList errors;
|
||||
try
|
||||
{
|
||||
auto sourceUnit = parseText(_source, errors);
|
||||
if (!sourceUnit)
|
||||
return false;
|
||||
}
|
||||
catch (FatalError const& _exception)
|
||||
{
|
||||
if (Error::containsErrorOfType(errors, Error::Type::ParserError))
|
||||
return false;
|
||||
}
|
||||
if (Error::containsErrorOfType(errors, Error::Type::ParserError))
|
||||
return false;
|
||||
|
||||
BOOST_CHECK(Error::containsOnlyWarnings(errors));
|
||||
return true;
|
||||
}
|
||||
|
||||
void checkFunctionNatspec(
|
||||
ASTPointer<FunctionDefinition> _function,
|
||||
std::string const& _expectedDoc
|
||||
)
|
||||
{
|
||||
auto doc = _function->documentation();
|
||||
BOOST_CHECK_MESSAGE(doc != nullptr, "Function does not have Natspec Doc as expected");
|
||||
@ -68,7 +92,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
char const* text = "contract test {\n"
|
||||
" uint256 stateVariable1;\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_variable_name_in_declaration)
|
||||
@ -76,7 +100,7 @@ BOOST_AUTO_TEST_CASE(missing_variable_name_in_declaration)
|
||||
char const* text = "contract test {\n"
|
||||
" uint256 ;\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_function)
|
||||
@ -87,7 +111,7 @@ BOOST_AUTO_TEST_CASE(empty_function)
|
||||
" returns (int id)\n"
|
||||
" { }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(no_function_params)
|
||||
@ -96,7 +120,7 @@ BOOST_AUTO_TEST_CASE(no_function_params)
|
||||
" uint256 stateVar;\n"
|
||||
" function functionName() {}\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(single_function_param)
|
||||
@ -105,7 +129,7 @@ BOOST_AUTO_TEST_CASE(single_function_param)
|
||||
" uint256 stateVar;\n"
|
||||
" function functionName(bytes32 input) returns (bytes32 out) {}\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_no_body)
|
||||
@ -113,7 +137,7 @@ BOOST_AUTO_TEST_CASE(function_no_body)
|
||||
char const* text = "contract test {\n"
|
||||
" function functionName(bytes32 input) returns (bytes32 out);\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_parameter_name_in_named_args)
|
||||
@ -122,7 +146,7 @@ BOOST_AUTO_TEST_CASE(missing_parameter_name_in_named_args)
|
||||
" function a(uint a, uint b, uint c) returns (uint r) { r = a * 100 + b * 10 + c * 1; }\n"
|
||||
" function b() returns (uint r) { r = a({: 1, : 2, : 3}); }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_argument_in_named_args)
|
||||
@ -131,7 +155,7 @@ BOOST_AUTO_TEST_CASE(missing_argument_in_named_args)
|
||||
" function a(uint a, uint b, uint c) returns (uint r) { r = a * 100 + b * 10 + c * 1; }\n"
|
||||
" function b() returns (uint r) { r = a({a: , b: , c: }); }\n"
|
||||
"}\n";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(two_exact_functions)
|
||||
@ -145,7 +169,7 @@ BOOST_AUTO_TEST_CASE(two_exact_functions)
|
||||
// with support of overloaded functions, during parsing,
|
||||
// we can't determine whether they match exactly, however
|
||||
// it will throw DeclarationError in following stage.
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(overloaded_functions)
|
||||
@ -156,20 +180,23 @@ BOOST_AUTO_TEST_CASE(overloaded_functions)
|
||||
function fun(uint a, uint b) returns(uint r) { return a + b; }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_natspec_documentation)
|
||||
{
|
||||
ASTPointer<ContractDefinition> contract;
|
||||
ASTPointer<FunctionDefinition> function;
|
||||
char const* text = "contract test {\n"
|
||||
" uint256 stateVar;\n"
|
||||
" /// This is a test function\n"
|
||||
" function functionName(bytes32 input) returns (bytes32 out) {}\n"
|
||||
"}\n";
|
||||
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
|
||||
auto functions = contract->definedFunctions();
|
||||
BOOST_CHECK(successParse(text));
|
||||
ErrorList e;
|
||||
ASTPointer<ContractDefinition> contract = parseText(text, e);
|
||||
ASTPointer<FunctionDefinition> function;
|
||||
|
||||
ErrorList errors;
|
||||
auto functions = parseText(text, errors)->definedFunctions();
|
||||
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
|
||||
checkFunctionNatspec(function, "This is a test function");
|
||||
}
|
||||
@ -183,8 +210,9 @@ BOOST_AUTO_TEST_CASE(function_normal_comments)
|
||||
" // We won't see this comment\n"
|
||||
" function functionName(bytes32 input) returns (bytes32 out) {}\n"
|
||||
"}\n";
|
||||
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
|
||||
auto functions = contract->definedFunctions();
|
||||
BOOST_CHECK(successParse(text));
|
||||
ErrorList errors;
|
||||
auto functions = parseText(text, errors)->definedFunctions();
|
||||
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
|
||||
BOOST_CHECK_MESSAGE(function->documentation() == nullptr,
|
||||
"Should not have gotten a Natspecc comment for this function");
|
||||
@ -205,8 +233,9 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
|
||||
" /// This is test function 4\n"
|
||||
" function functionName4(bytes32 input) returns (bytes32 out) {}\n"
|
||||
"}\n";
|
||||
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
|
||||
auto functions = contract->definedFunctions();
|
||||
BOOST_CHECK(successParse(text));
|
||||
ErrorList errors;
|
||||
auto functions = parseText(text, errors)->definedFunctions();
|
||||
|
||||
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
|
||||
checkFunctionNatspec(function, "This is test function 1");
|
||||
@ -232,9 +261,9 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation)
|
||||
" /// and it has 2 lines\n"
|
||||
" function functionName1(bytes32 input) returns (bytes32 out) {}\n"
|
||||
"}\n";
|
||||
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
|
||||
auto functions = contract->definedFunctions();
|
||||
|
||||
BOOST_CHECK(successParse(text));
|
||||
ErrorList errors;
|
||||
auto functions = parseText(text, errors)->definedFunctions();
|
||||
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
|
||||
checkFunctionNatspec(function, "This is a test function\n"
|
||||
" and it has 2 lines");
|
||||
@ -257,8 +286,9 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
|
||||
" /// and it has 2 lines\n"
|
||||
" function fun(bytes32 input) returns (bytes32 out) {}\n"
|
||||
"}\n";
|
||||
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
|
||||
auto functions = contract->definedFunctions();
|
||||
BOOST_CHECK(successParse(text));
|
||||
ErrorList errors;
|
||||
auto functions = parseText(text, errors)->definedFunctions();
|
||||
|
||||
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
|
||||
checkFunctionNatspec(function, "fun1 description");
|
||||
@ -283,8 +313,9 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature)
|
||||
" bytes7 name = \"Solidity\";"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
|
||||
auto functions = contract->definedFunctions();
|
||||
BOOST_CHECK(successParse(text));
|
||||
ErrorList errors;
|
||||
auto functions = parseText(text, errors)->definedFunctions();
|
||||
|
||||
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
|
||||
BOOST_CHECK_MESSAGE(!function->documentation(),
|
||||
@ -306,8 +337,9 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature)
|
||||
" bytes7 name = \"Solidity\";"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
|
||||
auto functions = contract->definedFunctions();
|
||||
BOOST_CHECK(successParse(text));
|
||||
ErrorList errors;
|
||||
auto functions = parseText(text, errors)->definedFunctions();
|
||||
|
||||
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
|
||||
BOOST_CHECK_MESSAGE(!function->documentation(),
|
||||
@ -323,7 +355,7 @@ BOOST_AUTO_TEST_CASE(struct_definition)
|
||||
" uint256 count;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(mapping)
|
||||
@ -331,7 +363,7 @@ BOOST_AUTO_TEST_CASE(mapping)
|
||||
char const* text = "contract test {\n"
|
||||
" mapping(address => bytes32) names;\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(mapping_in_struct)
|
||||
@ -343,7 +375,7 @@ BOOST_AUTO_TEST_CASE(mapping_in_struct)
|
||||
" mapping(bytes32 => test_struct) self_reference;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
|
||||
@ -354,7 +386,7 @@ BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
|
||||
" mapping (uint64 => mapping (bytes32 => uint)) complex_mapping;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(variable_definition)
|
||||
@ -367,7 +399,7 @@ BOOST_AUTO_TEST_CASE(variable_definition)
|
||||
" customtype varname;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
|
||||
@ -381,7 +413,7 @@ BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
|
||||
" customtype varname;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(variable_definition_in_function_parameter)
|
||||
@ -391,7 +423,7 @@ BOOST_AUTO_TEST_CASE(variable_definition_in_function_parameter)
|
||||
function fun(var a) {}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(variable_definition_in_mapping)
|
||||
@ -403,7 +435,7 @@ BOOST_AUTO_TEST_CASE(variable_definition_in_mapping)
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(variable_definition_in_function_return)
|
||||
@ -415,7 +447,7 @@ BOOST_AUTO_TEST_CASE(variable_definition_in_function_return)
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(operator_expression)
|
||||
@ -425,7 +457,7 @@ BOOST_AUTO_TEST_CASE(operator_expression)
|
||||
" uint256 x = (1 + 4) || false && (1 - 12) + -9;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(complex_expression)
|
||||
@ -435,7 +467,7 @@ BOOST_AUTO_TEST_CASE(complex_expression)
|
||||
" uint256 x = (1 + 4).member(++67)[a/=9] || true;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(exp_expression)
|
||||
@ -446,7 +478,7 @@ BOOST_AUTO_TEST_CASE(exp_expression)
|
||||
uint256 x = 3 ** a;
|
||||
}
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(while_loop)
|
||||
@ -456,7 +488,7 @@ BOOST_AUTO_TEST_CASE(while_loop)
|
||||
" while (true) { uint256 x = 1; break; continue; } x = 9;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(for_loop_vardef_initexpr)
|
||||
@ -467,7 +499,7 @@ BOOST_AUTO_TEST_CASE(for_loop_vardef_initexpr)
|
||||
" { uint256 x = i; break; continue; }\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(for_loop_simple_initexpr)
|
||||
@ -479,7 +511,7 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_initexpr)
|
||||
" { uint256 x = i; break; continue; }\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(for_loop_simple_noexpr)
|
||||
@ -491,7 +523,7 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_noexpr)
|
||||
" { uint256 x = i; break; continue; }\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(for_loop_single_stmt_body)
|
||||
@ -503,7 +535,7 @@ BOOST_AUTO_TEST_CASE(for_loop_single_stmt_body)
|
||||
" continue;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(if_statement)
|
||||
@ -513,7 +545,7 @@ BOOST_AUTO_TEST_CASE(if_statement)
|
||||
" if (a >= 8) return 2; else { var b = 7; }\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(else_if_statement)
|
||||
@ -523,7 +555,7 @@ BOOST_AUTO_TEST_CASE(else_if_statement)
|
||||
" if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
|
||||
@ -535,7 +567,7 @@ BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
|
||||
" uint64[](3);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(type_conversion_to_dynamic_array)
|
||||
@ -545,7 +577,7 @@ BOOST_AUTO_TEST_CASE(type_conversion_to_dynamic_array)
|
||||
" var x = uint64[](3);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(import_directive)
|
||||
@ -556,7 +588,7 @@ BOOST_AUTO_TEST_CASE(import_directive)
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_contracts)
|
||||
@ -571,7 +603,7 @@ BOOST_AUTO_TEST_CASE(multiple_contracts)
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports)
|
||||
@ -589,7 +621,7 @@ BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports)
|
||||
" }\n"
|
||||
"}\n"
|
||||
"import \"ghi\";\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(contract_inheritance)
|
||||
@ -604,7 +636,7 @@ BOOST_AUTO_TEST_CASE(contract_inheritance)
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(contract_multiple_inheritance)
|
||||
@ -619,7 +651,7 @@ BOOST_AUTO_TEST_CASE(contract_multiple_inheritance)
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments)
|
||||
@ -634,7 +666,7 @@ BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments)
|
||||
" uint64(2);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(placeholder_in_function_context)
|
||||
@ -645,7 +677,7 @@ BOOST_AUTO_TEST_CASE(placeholder_in_function_context)
|
||||
" return _ + 1;"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(modifier)
|
||||
@ -653,7 +685,7 @@ BOOST_AUTO_TEST_CASE(modifier)
|
||||
char const* text = "contract c {\n"
|
||||
" modifier mod { if (msg.sender == 0) _ }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(modifier_arguments)
|
||||
@ -661,7 +693,7 @@ BOOST_AUTO_TEST_CASE(modifier_arguments)
|
||||
char const* text = "contract c {\n"
|
||||
" modifier mod(uint a) { if (msg.sender == a) _ }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(modifier_invocation)
|
||||
@ -671,7 +703,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation)
|
||||
" modifier mod2 { if (msg.sender == 2) _ }\n"
|
||||
" function f() mod1(7) mod2 { }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fallback_function)
|
||||
@ -679,7 +711,7 @@ BOOST_AUTO_TEST_CASE(fallback_function)
|
||||
char const* text = "contract c {\n"
|
||||
" function() { }\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event)
|
||||
@ -688,7 +720,7 @@ BOOST_AUTO_TEST_CASE(event)
|
||||
contract c {
|
||||
event e();
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_arguments)
|
||||
@ -697,7 +729,7 @@ BOOST_AUTO_TEST_CASE(event_arguments)
|
||||
contract c {
|
||||
event e(uint a, bytes32 s);
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_arguments_indexed)
|
||||
@ -706,7 +738,7 @@ BOOST_AUTO_TEST_CASE(event_arguments_indexed)
|
||||
contract c {
|
||||
event e(uint a, bytes32 indexed s, bool indexed b);
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(visibility_specifiers)
|
||||
@ -722,7 +754,7 @@ BOOST_AUTO_TEST_CASE(visibility_specifiers)
|
||||
function f_public() public {}
|
||||
function f_internal() internal {}
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
|
||||
@ -731,7 +763,7 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
|
||||
contract c {
|
||||
uint private internal a;
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
|
||||
@ -750,7 +782,7 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
|
||||
uint256 c;
|
||||
uint256 d;
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expressions)
|
||||
@ -763,7 +795,7 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expression
|
||||
}
|
||||
uint256 a;
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(enum_valid_declaration)
|
||||
@ -777,7 +809,7 @@ BOOST_AUTO_TEST_CASE(enum_valid_declaration)
|
||||
}
|
||||
uint256 a;
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_enum_declaration)
|
||||
@ -786,7 +818,7 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration)
|
||||
contract c {
|
||||
enum foo { }
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_enum_declaration)
|
||||
@ -795,7 +827,7 @@ BOOST_AUTO_TEST_CASE(malformed_enum_declaration)
|
||||
contract c {
|
||||
enum foo { WARNING,}
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(external_function)
|
||||
@ -804,7 +836,7 @@ BOOST_AUTO_TEST_CASE(external_function)
|
||||
contract c {
|
||||
function x() external {}
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(external_variable)
|
||||
@ -813,7 +845,7 @@ BOOST_AUTO_TEST_CASE(external_variable)
|
||||
contract c {
|
||||
uint external x;
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(arrays_in_storage)
|
||||
@ -825,7 +857,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_storage)
|
||||
struct x { uint[2**20] b; y[0] c; }
|
||||
struct y { uint d; mapping(uint=>x)[] e; }
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(arrays_in_events)
|
||||
@ -834,7 +866,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_events)
|
||||
contract c {
|
||||
event e(uint[10] a, bytes7[8] indexed b, c[3] x);
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(arrays_in_expressions)
|
||||
@ -843,7 +875,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_expressions)
|
||||
contract c {
|
||||
function f() { c[10] a = 7; uint8[10 * 2] x; }
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multi_arrays)
|
||||
@ -852,7 +884,7 @@ BOOST_AUTO_TEST_CASE(multi_arrays)
|
||||
contract c {
|
||||
mapping(uint => mapping(uint => int8)[8][][9])[] x;
|
||||
})";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constant_is_keyword)
|
||||
@ -861,7 +893,7 @@ BOOST_AUTO_TEST_CASE(constant_is_keyword)
|
||||
contract Foo {
|
||||
uint constant = 4;
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(var_array)
|
||||
@ -870,7 +902,7 @@ BOOST_AUTO_TEST_CASE(var_array)
|
||||
contract Foo {
|
||||
function f() { var[] a; }
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(location_specifiers_for_params)
|
||||
@ -880,7 +912,7 @@ BOOST_AUTO_TEST_CASE(location_specifiers_for_params)
|
||||
function f(uint[] storage constant x, uint[] memory y) { }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(location_specifiers_for_locals)
|
||||
@ -893,7 +925,7 @@ BOOST_AUTO_TEST_CASE(location_specifiers_for_locals)
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(location_specifiers_for_state)
|
||||
@ -902,7 +934,7 @@ BOOST_AUTO_TEST_CASE(location_specifiers_for_state)
|
||||
contract Foo {
|
||||
uint[] memory x;
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(location_specifiers_with_var)
|
||||
@ -911,7 +943,7 @@ BOOST_AUTO_TEST_CASE(location_specifiers_with_var)
|
||||
contract Foo {
|
||||
function f() { var memory x; }
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseText(text), ParserError);
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_comment)
|
||||
@ -921,7 +953,7 @@ BOOST_AUTO_TEST_CASE(empty_comment)
|
||||
contract test
|
||||
{}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(library_simple)
|
||||
@ -931,7 +963,21 @@ BOOST_AUTO_TEST_CASE(library_simple)
|
||||
function f() { }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(local_const_variable)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract Foo {
|
||||
function localConst() returns (uint ret)
|
||||
{
|
||||
uint constant local = 4;
|
||||
return local;
|
||||
}
|
||||
})";
|
||||
BOOST_CHECK(!successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multi_variable_declaration)
|
||||
@ -951,7 +997,7 @@ BOOST_AUTO_TEST_CASE(multi_variable_declaration)
|
||||
function g() returns (uint, uint, uint) {}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseText(text));
|
||||
BOOST_CHECK(successParse(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -67,12 +67,26 @@ public:
|
||||
return m_output;
|
||||
}
|
||||
|
||||
template <class Exceptiontype>
|
||||
void compileRequireThrow(std::string const& _sourceCode)
|
||||
void compileRequireError(std::string const& _sourceCode, Error::Type _type)
|
||||
{
|
||||
m_compiler.reset(false, m_addStandardSources);
|
||||
m_compiler.addSource("", _sourceCode);
|
||||
BOOST_REQUIRE_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), Exceptiontype);
|
||||
bool foundError = false;
|
||||
try
|
||||
{
|
||||
m_compiler.compile(m_optimize, m_optimizeRuns);
|
||||
BOOST_REQUIRE(Error::containsErrorOfType(m_compiler.errors(), _type));
|
||||
}
|
||||
catch (Error const& _e)
|
||||
{
|
||||
BOOST_REQUIRE(_e.type() == _type);
|
||||
foundError = true;
|
||||
}
|
||||
catch (Exception const& _exception)
|
||||
{
|
||||
BOOST_REQUIRE(false);
|
||||
}
|
||||
BOOST_REQUIRE(foundError);
|
||||
}
|
||||
|
||||
bytes const& compileAndRun(
|
||||
|
Loading…
Reference in New Issue
Block a user