Browse Source

Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

cl-refactor
Gav Wood 10 years ago
parent
commit
c1aff839ff
  1. 4
      libdevcore/Exceptions.h
  2. 2
      libdevcrypto/TrieDB.h
  3. 2
      libethereum/BlockChain.cpp
  4. 51
      libsolidity/AST.cpp
  5. 1
      libsolidity/AST.h
  6. 205
      libsolidity/ArrayUtils.cpp
  7. 5
      libsolidity/ArrayUtils.h
  8. 11
      libsolidity/Compiler.cpp
  9. 8
      libsolidity/CompilerUtils.cpp
  10. 3
      libsolidity/CompilerUtils.h
  11. 18
      libsolidity/ExpressionCompiler.cpp
  12. 1
      libsolidity/LValue.cpp
  13. 5
      libsolidity/Types.cpp
  14. 14
      libsolidity/Types.h
  15. 12
      test/SolidityABIJSON.cpp
  16. 99
      test/SolidityEndToEndTest.cpp
  17. 10
      test/SolidityExpressionCompiler.cpp
  18. 6
      test/SolidityInterface.cpp
  19. 137
      test/SolidityNameAndTypeResolution.cpp
  20. 12
      test/SolidityNatspecJSON.cpp
  21. 146
      test/SolidityParser.cpp
  22. 37
      test/TestHelper.h
  23. 14
      test/solidityExecutionFramework.h

4
libdevcore/Exceptions.h

@ -33,8 +33,8 @@ namespace dev
// base class for all exceptions // base class for all exceptions
struct Exception: virtual std::exception, virtual boost::exception struct Exception: virtual std::exception, virtual boost::exception
{ {
Exception(std::string _message = {}) : m_message(std::move(_message)) {} Exception(std::string _message = {}): m_message(std::move(_message)) {}
const char* what() const noexcept override { return m_message.c_str(); } const char* what() const noexcept override { return m_message.empty() ? std::exception::what() : m_message.c_str(); }
private: private:
std::string m_message; std::string m_message;

2
libdevcrypto/TrieDB.h

@ -417,7 +417,7 @@ public:
void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(_key, _value); m_secure.insert(_key, _value); syncRoot(); } void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(_key, _value); m_secure.insert(_key, _value); syncRoot(); }
void remove(bytesConstRef _key) { Super::remove(_key); m_secure.remove(_key); syncRoot(); } void remove(bytesConstRef _key) { Super::remove(_key); m_secure.remove(_key); syncRoot(); }
std::set<h256> leftOvers(std::ostream* = nullptr) const { return {}; } std::set<h256> leftOvers(std::ostream* = nullptr) const { return std::set<h256>{}; }
bool check(bool) const { return m_secure.check(false) && Super::check(false); } bool check(bool) const { return m_secure.check(false) && Super::check(false); }
private: private:

2
libethereum/BlockChain.cpp

@ -547,7 +547,7 @@ void BlockChain::garbageCollect(bool _force)
} }
} }
m_cacheUsage.pop_back(); m_cacheUsage.pop_back();
m_cacheUsage.push_front({}); m_cacheUsage.push_front(std::set<CacheID>{});
} }
void BlockChain::checkConsistency() void BlockChain::checkConsistency()

51
libsolidity/AST.cpp

@ -328,8 +328,30 @@ bool VariableDeclaration::isLValue() const
void VariableDeclaration::checkTypeRequirements() void VariableDeclaration::checkTypeRequirements()
{ {
if (m_value) // Variables can be declared without type (with "var"), in which case the first assignment
// sets the type.
// Note that assignments before the first declaration are legal because of the special scoping
// rules inherited from JavaScript.
if (!m_value)
return;
if (m_type)
m_value->expectType(*m_type);
else
{
// no type declared and no previous assignment, infer the type
m_value->checkTypeRequirements(); m_value->checkTypeRequirements();
TypePointer type = m_value->getType();
if (type->getCategory() == Type::Category::IntegerConstant)
{
auto intType = dynamic_pointer_cast<IntegerConstantType const>(type)->getIntegerType();
if (!intType)
BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString() + "."));
type = intType;
}
else if (type->getCategory() == Type::Category::Void)
BOOST_THROW_EXCEPTION(createTypeError("Variable cannot have void type."));
m_type = type;
}
} }
bool VariableDeclaration::isExternalFunctionParameter() const bool VariableDeclaration::isExternalFunctionParameter() const
@ -445,32 +467,9 @@ void Return::checkTypeRequirements()
void VariableDeclarationStatement::checkTypeRequirements() void VariableDeclarationStatement::checkTypeRequirements()
{ {
// Variables can be declared without type (with "var"), in which case the first assignment m_variable->checkTypeRequirements();
// sets the type.
// Note that assignments before the first declaration are legal because of the special scoping
// rules inherited from JavaScript.
if (m_variable->getValue())
{
if (m_variable->getType())
m_variable->getValue()->expectType(*m_variable->getType());
else
{
// no type declared and no previous assignment, infer the type
m_variable->getValue()->checkTypeRequirements();
TypePointer type = m_variable->getValue()->getType();
if (type->getCategory() == Type::Category::IntegerConstant)
{
auto intType = dynamic_pointer_cast<IntegerConstantType const>(type)->getIntegerType();
if (!intType)
BOOST_THROW_EXCEPTION(m_variable->getValue()->createTypeError("Invalid integer constant " + type->toString()));
type = intType;
}
else if (type->getCategory() == Type::Category::Void)
BOOST_THROW_EXCEPTION(m_variable->createTypeError("var cannot be void type"));
m_variable->setType(type);
}
}
} }
void Assignment::checkTypeRequirements() void Assignment::checkTypeRequirements()
{ {
m_leftHandSide->checkTypeRequirements(); m_leftHandSide->checkTypeRequirements();

1
libsolidity/AST.h

@ -460,7 +460,6 @@ public:
virtual bool isLValue() const override; virtual bool isLValue() const override;
/// Calls checkTypeRequirments for all state variables.
void checkTypeRequirements(); void checkTypeRequirements();
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); } bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
bool isExternalFunctionParameter() const; bool isExternalFunctionParameter() const;

205
libsolidity/ArrayUtils.cpp

@ -37,140 +37,120 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// stack layout: [source_ref] target_ref (top) // stack layout: [source_ref] target_ref (top)
// need to leave target_ref on the stack at the end // need to leave target_ref on the stack at the end
solAssert(_targetType.getLocation() == ArrayType::Location::Storage, ""); solAssert(_targetType.getLocation() == ArrayType::Location::Storage, "");
solAssert(
_sourceType.getLocation() == ArrayType::Location::CallData ||
_sourceType.getLocation() == ArrayType::Location::Storage,
"Given array location not implemented."
);
IntegerType uint256(256); IntegerType uint256(256);
Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType()); Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType());
Type const* sourceBaseType = _sourceType.isByteArray() ? &uint256 : &(*_sourceType.getBaseType()); Type const* sourceBaseType = _sourceType.isByteArray() ? &uint256 : &(*_sourceType.getBaseType());
switch (_sourceType.getLocation())
{
case ArrayType::Location::CallData:
{
solAssert(_targetType.isByteArray(), "Non byte arrays not yet implemented here.");
solAssert(_sourceType.isByteArray(), "Non byte arrays not yet implemented here.");
// This also assumes that after "length" we only have zeros, i.e. it cannot be used to
// slice a byte array from calldata.
// stack: source_offset source_len target_ref
// fetch old length and convert to words
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
convertLengthToSize(_targetType);
// stack here: source_offset source_len target_ref target_length_words
// actual array data is stored at SHA3(storage_offset)
m_context << eth::Instruction::DUP2;
CompilerUtils(m_context).computeHashStatic();
// compute target_data_end
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack here: source_offset source_len target_ref target_data_end target_data_ref
// store length (in bytes)
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5
<< eth::Instruction::SSTORE;
// jump to end if length is zero
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// add length to source offset
m_context << eth::Instruction::DUP5 << eth::Instruction::DUP5 << eth::Instruction::ADD;
// stack now: source_offset source_len target_ref target_data_end target_data_ref source_end
// store start offset
m_context << eth::Instruction::DUP6;
// stack now: source_offset source_len target_ref target_data_end target_data_ref source_end calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart
// copy from calldata and store
<< eth::Instruction::DUP1 << eth::Instruction::CALLDATALOAD
<< eth::Instruction::DUP4 << eth::Instruction::SSTORE
// increment target_data_ref by 1
<< eth::Instruction::SWAP2 << u256(1) << eth::Instruction::ADD
// increment calldata_offset by 32
<< eth::Instruction::SWAP2 << u256(32) << eth::Instruction::ADD
// check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(copyLoopStart);
m_context << eth::Instruction::POP << eth::Instruction::POP;
m_context << copyLoopEnd;
// now clear leftover bytes of the old value
// stack now: source_offset source_len target_ref target_data_end target_data_ref
clearStorageLoop(IntegerType(256));
// stack now: source_offset source_len target_ref target_data_end
m_context << eth::Instruction::POP << eth::Instruction::SWAP2
<< eth::Instruction::POP << eth::Instruction::POP;
break;
}
case ArrayType::Location::Storage:
{
// this copies source to target and also clears target if it was larger // this copies source to target and also clears target if it was larger
solAssert(sourceBaseType->getStorageSize() == targetBaseType->getStorageSize(), // TODO unroll loop for small sizes
"Copying with different storage sizes not yet implemented.");
// stack: source_ref target_ref // stack: source_ref [source_length] target_ref
// store target_ref // store target_ref
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2; for (unsigned i = _sourceType.getSizeOnStack(); i > 0; --i)
// stack: target_ref source_ref target_ref m_context << eth::swapInstruction(i);
// fetch lengthes if (_sourceType.getLocation() != ArrayType::Location::CallData || !_sourceType.isDynamicallySized())
retrieveLength(_sourceType); // otherwise, length is already there
// stack: target_ref source_ref source_length
m_context << eth::Instruction::DUP3;
// stack: target_ref source_ref source_length target_ref
retrieveLength(_targetType); retrieveLength(_targetType);
m_context << eth::Instruction::SWAP2; // stack: target_ref source_ref source_length target_ref target_length
// stack: target_ref target_len target_ref source_ref
retrieveLength(_sourceType);
// stack: target_ref target_len target_ref source_ref source_len
if (_targetType.isDynamicallySized()) if (_targetType.isDynamicallySized())
// store new target length // store new target length
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SSTORE; m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3 << eth::Instruction::SSTORE;
if (sourceBaseType->getCategory() == Type::Category::Mapping)
{
solAssert(targetBaseType->getCategory() == Type::Category::Mapping, "");
solAssert(_sourceType.getLocation() == ArrayType::Location::Storage, "");
// nothing to copy
m_context
<< eth::Instruction::POP << eth::Instruction::POP
<< eth::Instruction::POP << eth::Instruction::POP;
return;
}
// compute hashes (data positions) // compute hashes (data positions)
m_context << eth::Instruction::SWAP2; m_context << eth::Instruction::SWAP1;
if (_targetType.isDynamicallySized()) if (_targetType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
// stack: target_ref source_ref source_length target_length target_data_pos
m_context << eth::Instruction::SWAP1; m_context << eth::Instruction::SWAP1;
if (_sourceType.isDynamicallySized()) convertLengthToSize(_targetType);
m_context << eth::Instruction::DUP2 << eth::Instruction::ADD;
// stack: target_ref source_ref source_length target_data_pos target_data_end
m_context << eth::Instruction::SWAP3;
// stack: target_ref target_data_end source_length target_data_pos source_ref
// skip copying if source length is zero
m_context << eth::Instruction::DUP3 << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
if (_sourceType.getLocation() == ArrayType::Location::Storage && _sourceType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
// stack: target_ref target_len source_len target_data_pos source_data_pos // stack: target_ref target_data_end source_length target_data_pos source_data_pos
m_context << eth::Instruction::DUP4; m_context << eth::Instruction::SWAP2;
convertLengthToSize(_sourceType);
m_context << eth::Instruction::DUP4;
convertLengthToSize(_sourceType); convertLengthToSize(_sourceType);
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
// @todo we might be able to go without a third counter // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
m_context << u256(0);
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size counter
eth::AssemblyItem copyLoopStart = m_context.newTag(); eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart; m_context << copyLoopStart;
// check for loop condition // check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 m_context
<< eth::Instruction::DUP3 << eth::Instruction::DUP2
<< eth::Instruction::GT << eth::Instruction::ISZERO; << eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd); m_context.appendConditionalJumpTo(copyLoopEnd);
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
// copy // copy
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP2 << eth::Instruction::ADD; if (sourceBaseType->getCategory() == Type::Category::Array)
{
m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3;
copyArrayToStorage(
dynamic_cast<ArrayType const&>(*targetBaseType),
dynamic_cast<ArrayType const&>(*sourceBaseType)
);
m_context << eth::Instruction::POP;
}
else
{
m_context << eth::Instruction::DUP3;
if (_sourceType.getLocation() == ArrayType::Location::Storage)
StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true); StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true);
m_context << eth::dupInstruction(5 + sourceBaseType->getSizeOnStack()) else if (sourceBaseType->isValueType())
<< eth::dupInstruction(2 + sourceBaseType->getSizeOnStack()) << eth::Instruction::ADD; CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, true, true, false);
else
solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString());
m_context << eth::dupInstruction(2 + sourceBaseType->getSizeOnStack());
StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true); StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
// increment }
m_context << targetBaseType->getStorageSize() << eth::Instruction::ADD; // increment source
m_context
<< eth::Instruction::SWAP2
<< (_sourceType.getLocation() == ArrayType::Location::Storage ?
sourceBaseType->getStorageSize() :
sourceBaseType->getCalldataEncodedSize())
<< eth::Instruction::ADD
<< eth::Instruction::SWAP2;
// increment target
m_context
<< eth::Instruction::SWAP1
<< targetBaseType->getStorageSize()
<< eth::Instruction::ADD
<< eth::Instruction::SWAP1;
m_context.appendJumpTo(copyLoopStart); m_context.appendJumpTo(copyLoopStart);
m_context << copyLoopEnd; m_context << copyLoopEnd;
// zero-out leftovers in target // zero-out leftovers in target
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size counter // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
// add counter to target_data_pos m_context << eth::Instruction::POP << eth::Instruction::SWAP1 << eth::Instruction::POP;
m_context << eth::Instruction::DUP5 << eth::Instruction::ADD
<< eth::Instruction::SWAP5 << eth::Instruction::POP;
// stack: target_ref target_len target_data_pos_updated target_data_pos source_data_pos target_size source_size
// add size to target_data_pos to get target_data_end
m_context << eth::Instruction::POP << eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP4
<< eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated // stack: target_ref target_data_end target_data_pos_updated
clearStorageLoop(*targetBaseType); clearStorageLoop(*targetBaseType);
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
break;
}
default:
solAssert(false, "Given byte array location not implemented.");
}
} }
void ArrayUtils::clearArray(ArrayType const& _type) const void ArrayUtils::clearArray(ArrayType const& _type) const
@ -178,7 +158,7 @@ void ArrayUtils::clearArray(ArrayType const& _type) const
solAssert(_type.getLocation() == ArrayType::Location::Storage, ""); solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
if (_type.isDynamicallySized()) if (_type.isDynamicallySized())
clearDynamicArray(_type); clearDynamicArray(_type);
else if (_type.getLength() == 0) else if (_type.getLength() == 0 || _type.getBaseType()->getCategory() == Type::Category::Mapping)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
else if (_type.getLength() < 5) // unroll loop for small arrays @todo choose a good value else if (_type.getLength() < 5) // unroll loop for small arrays @todo choose a good value
{ {
@ -272,6 +252,11 @@ void ArrayUtils::resizeDynamicArray(const ArrayType& _type) const
void ArrayUtils::clearStorageLoop(Type const& _type) const void ArrayUtils::clearStorageLoop(Type const& _type) const
{ {
if (_type.getCategory() == Type::Category::Mapping)
{
m_context << eth::Instruction::POP;
return;
}
// stack: end_pos pos // stack: end_pos pos
eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart; m_context << loopStart;
@ -290,13 +275,25 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }
void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType) const void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) const
{ {
if (_arrayType.getLocation() == ArrayType::Location::Storage)
{
if (_arrayType.isByteArray()) if (_arrayType.isByteArray())
m_context << u256(31) << eth::Instruction::ADD m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV; << u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
else if (_arrayType.getBaseType()->getStorageSize() > 1) else if (_arrayType.getBaseType()->getStorageSize() > 1)
m_context << _arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL; m_context << _arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL;
}
else
{
if (!_arrayType.isByteArray())
m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL;
else if (_pad)
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::DUP1
<< eth::Instruction::SWAP2 << eth::Instruction::DIV << eth::Instruction::MUL;
}
} }
void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const

5
libsolidity/ArrayUtils.h

@ -60,10 +60,11 @@ public:
/// Stack pre: end_ref start_ref /// Stack pre: end_ref start_ref
/// Stack post: end_ref /// Stack post: end_ref
void clearStorageLoop(Type const& _type) const; void clearStorageLoop(Type const& _type) const;
/// Converts length to size (multiplies by size on stack), rounds up for byte arrays. /// Converts length to size (number of storage slots or calldata/memory bytes).
/// if @a _pad then add padding to multiples of 32 bytes for calldata/memory.
/// Stack pre: length /// Stack pre: length
/// Stack post: size /// Stack post: size
void convertLengthToSize(ArrayType const& _arrayType) const; void convertLengthToSize(ArrayType const& _arrayType, bool _pad = false) const;
/// Retrieves the length (number of elements) of the array ref on the stack. This also /// Retrieves the length (number of elements) of the array ref on the stack. This also
/// works for statically-sized arrays. /// works for statically-sized arrays.
/// Stack pre: reference /// Stack pre: reference

11
libsolidity/Compiler.cpp

@ -150,7 +150,7 @@ void Compiler::appendConstructor(FunctionDefinition const& _constructor)
// copy constructor arguments from code to memory and then to stack, they are supplied after the actual program // copy constructor arguments from code to memory and then to stack, they are supplied after the actual program
unsigned argumentSize = 0; unsigned argumentSize = 0;
for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters()) for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters())
argumentSize += CompilerUtils::getPaddedSize(var->getType()->getCalldataEncodedSize()); argumentSize += var->getType()->getCalldataEncodedSize();
if (argumentSize > 0) if (argumentSize > 0)
{ {
@ -208,8 +208,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
bigint parameterHeadEnd = offset; bigint parameterHeadEnd = offset;
for (TypePointer const& type: _typeParameters) for (TypePointer const& type: _typeParameters)
parameterHeadEnd += type->isDynamicallySized() ? 32 : parameterHeadEnd += type->isDynamicallySized() ? 32 : type->getCalldataEncodedSize();
CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
solAssert(parameterHeadEnd <= numeric_limits<unsigned>::max(), "Arguments too large."); solAssert(parameterHeadEnd <= numeric_limits<unsigned>::max(), "Arguments too large.");
unsigned stackHeightOfPreviousDynamicArgument = 0; unsigned stackHeightOfPreviousDynamicArgument = 0;
@ -228,8 +227,8 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
// Retrieve data start offset by adding length to start offset of previous dynamic type // Retrieve data start offset by adding length to start offset of previous dynamic type
unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument; unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument;
m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth); m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth);
ArrayUtils(m_context).convertLengthToSize(*previousDynamicType); ArrayUtils(m_context).convertLengthToSize(*previousDynamicType, true);
m_context << u256(32) << eth::Instruction::MUL << eth::Instruction::ADD; m_context << eth::Instruction::ADD;
} }
else else
m_context << u256(parameterHeadEnd); m_context << u256(parameterHeadEnd);
@ -240,7 +239,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
else else
{ {
m_context << u256(offset); m_context << u256(offset);
offset += CompilerUtils::getPaddedSize(type->getCalldataEncodedSize()); offset += type->getCalldataEncodedSize();
} }
break; break;
default: default:

8
libsolidity/CompilerUtils.cpp

@ -92,7 +92,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
} }
else else
{ {
solAssert(type.getLocation() == ArrayType::Location::Storage, "Memory byte arrays not yet implemented."); solAssert(type.getLocation() == ArrayType::Location::Storage, "Memory arrays not yet implemented.");
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// stack here: memory_offset storage_offset length_bytes // stack here: memory_offset storage_offset length_bytes
// jump to end if length is zero // jump to end if length is zero
@ -177,8 +177,7 @@ void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundari
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{ {
unsigned _encodedSize = _type.getCalldataEncodedSize(); unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
bool leftAligned = _type.getCategory() == Type::Category::String; bool leftAligned = _type.getCategory() == Type::Category::String;
if (numBytes == 0) if (numBytes == 0)
m_context << eth::Instruction::POP << u256(0); m_context << eth::Instruction::POP << u256(0);
@ -202,8 +201,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
{ {
unsigned _encodedSize = _type.getCalldataEncodedSize(); unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
bool leftAligned = _type.getCategory() == Type::Category::String; bool leftAligned = _type.getCategory() == Type::Category::String;
if (numBytes == 0) if (numBytes == 0)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;

3
libsolidity/CompilerUtils.h

@ -71,9 +71,6 @@ public:
/// Stack pre: memory_offset value... /// Stack pre: memory_offset value...
/// Stack post: (memory_offset+length) /// Stack post: (memory_offset+length)
void storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries = true); void storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries = true);
/// @returns _size rounded up to the next multiple of 32 (the number of bytes occupied in the
/// padded calldata)
static unsigned getPaddedSize(unsigned _size) { return ((_size + 31) / 32) * 32; }
/// Moves the value that is at the top of the stack to a stack variable. /// Moves the value that is at the top of the stack to a stack variable.
void moveToStackVariable(VariableDeclaration const& _variable); void moveToStackVariable(VariableDeclaration const& _variable);

18
libsolidity/ExpressionCompiler.cpp

@ -74,7 +74,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{ {
// move offset to memory // move offset to memory
CompilerUtils(m_context).storeInMemory(length); CompilerUtils(m_context).storeInMemory(length);
unsigned argLen = CompilerUtils::getPaddedSize(paramType->getCalldataEncodedSize()); unsigned argLen = paramType->getCalldataEncodedSize();
length -= argLen; length -= argLen;
m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3; m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3;
@ -782,8 +782,9 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
else else
{ {
u256 elementSize = u256 elementSize =
location == ArrayType::Location::Storage ? arrayType.getBaseType()->getStorageSize() : location == ArrayType::Location::Storage ?
CompilerUtils::getPaddedSize(arrayType.getBaseType()->getCalldataEncodedSize()); arrayType.getBaseType()->getStorageSize() :
arrayType.getBaseType()->getCalldataEncodedSize();
solAssert(elementSize != 0, "Invalid element size."); solAssert(elementSize != 0, "Invalid element size.");
if (elementSize > 1) if (elementSize > 1)
m_context << elementSize << eth::Instruction::MUL; m_context << elementSize << eth::Instruction::MUL;
@ -801,7 +802,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
switch (location) switch (location)
{ {
case ArrayType::Location::CallData: case ArrayType::Location::CallData:
// no lvalue if (arrayType.getBaseType()->isValueType())
CompilerUtils(m_context).loadFromMemoryDynamic(*arrayType.getBaseType(), true, true, false); CompilerUtils(m_context).loadFromMemoryDynamic(*arrayType.getBaseType(), true, true, false);
break; break;
case ArrayType::Location::Storage: case ArrayType::Location::Storage:
@ -1021,7 +1022,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
//@todo only return the first return value for now //@todo only return the first return value for now
Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr :
_functionType.getReturnParameterTypes().front().get(); _functionType.getReturnParameterTypes().front().get();
unsigned retSize = firstType ? CompilerUtils::getPaddedSize(firstType->getCalldataEncodedSize()) : 0; unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
m_context << u256(retSize) << u256(0); m_context << u256(retSize) << u256(0);
if (bare) if (bare)
@ -1051,8 +1052,9 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
if (_functionType.gasSet()) if (_functionType.gasSet())
m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
else else
// send all gas except for the 21 needed to execute "SUB" and "CALL" // send all gas except the amount needed to execute "SUB" and "CALL"
m_context << u256(_functionType.valueSet() ? 6741 : 41) << eth::Instruction::GAS << eth::Instruction::SUB; // @todo this retains too much gas for now, needs to be fine-tuned.
m_context << u256(50 + (_functionType.valueSet() ? 9000 : 0)) << eth::Instruction::GAS << eth::Instruction::SUB;
m_context << eth::Instruction::CALL; m_context << eth::Instruction::CALL;
auto tag = m_context.appendConditionalJump(); auto tag = m_context.appendConditionalJump();
m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0. m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.
@ -1083,7 +1085,7 @@ void ExpressionCompiler::appendArgumentsCopyToMemory(
appendTypeConversion(*_arguments[i]->getType(), *expectedType, true); appendTypeConversion(*_arguments[i]->getType(), *expectedType, true);
bool pad = _padToWordBoundaries; bool pad = _padToWordBoundaries;
// Do not pad if the first argument has exactly four bytes // Do not pad if the first argument has exactly four bytes
if (i == 0 && pad && _padExceptionIfFourBytes && expectedType->getCalldataEncodedSize() == 4) if (i == 0 && pad && _padExceptionIfFourBytes && expectedType->getCalldataEncodedSize(false) == 4)
pad = false; pad = false;
appendTypeMoveToMemory(*expectedType, pad); appendTypeMoveToMemory(*expectedType, pad);
} }

1
libsolidity/LValue.cpp

@ -212,6 +212,7 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
} }
else else
{ {
solAssert(m_dataType.isValueType(), "Clearing of unsupported type requested: " + m_dataType.toString());
if (m_size == 0 && _removeReference) if (m_size == 0 && _removeReference)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
else if (m_size == 1) else if (m_size == 1)

5
libsolidity/Types.cpp

@ -589,11 +589,12 @@ bool ArrayType::operator==(Type const& _other) const
return isDynamicallySized() || getLength() == other.getLength(); return isDynamicallySized() || getLength() == other.getLength();
} }
unsigned ArrayType::getCalldataEncodedSize() const unsigned ArrayType::getCalldataEncodedSize(bool _padded) const
{ {
if (isDynamicallySized()) if (isDynamicallySized())
return 0; return 0;
bigint size = bigint(getLength()) * (isByteArray() ? 1 : getBaseType()->getCalldataEncodedSize()); bigint size = bigint(getLength()) * (isByteArray() ? 1 : getBaseType()->getCalldataEncodedSize(_padded));
size = ((size + 31) / 32) * 32;
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned."); solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned.");
return unsigned(size); return unsigned(size);
} }

14
libsolidity/Types.h

@ -120,8 +120,10 @@ public:
/// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding /// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding
/// is not a simple big-endian encoding or the type cannot be stored in calldata. /// is not a simple big-endian encoding or the type cannot be stored in calldata.
/// Note that irrespective of this size, each calldata element is padded to a multiple of 32 bytes. /// If @a _padded then it is assumed that each element is padded to a multiple of 32 bytes.
virtual unsigned getCalldataEncodedSize() const { return 0; } virtual unsigned getCalldataEncodedSize(bool _padded) const { (void)_padded; return 0; }
/// Convenience version of @see getCalldataEncodedSize(bool)
unsigned getCalldataEncodedSize() const { return getCalldataEncodedSize(true); }
/// @returns true if the type is dynamically encoded in calldata /// @returns true if the type is dynamically encoded in calldata
virtual bool isDynamicallySized() const { return false; } virtual bool isDynamicallySized() const { return false; }
/// @returns number of bytes required to hold this value in storage. /// @returns number of bytes required to hold this value in storage.
@ -176,7 +178,7 @@ public:
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize() const override { return m_bits / 8; } virtual unsigned getCalldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_bits / 8; }
virtual bool isValueType() const override { return true; } virtual bool isValueType() const override { return true; }
virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; } virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; }
@ -247,7 +249,7 @@ public:
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize() const override { return m_bytes; } virtual unsigned getCalldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
virtual bool isValueType() const override { return true; } virtual bool isValueType() const override { return true; }
virtual std::string toString() const override { return "string" + dev::toString(m_bytes); } virtual std::string toString() const override { return "string" + dev::toString(m_bytes); }
@ -271,7 +273,7 @@ public:
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
virtual unsigned getCalldataEncodedSize() const { return 1; } virtual unsigned getCalldataEncodedSize(bool _padded) const { return _padded ? 32 : 1; }
virtual bool isValueType() const override { return true; } virtual bool isValueType() const override { return true; }
virtual std::string toString() const override { return "bool"; } virtual std::string toString() const override { return "bool"; }
@ -302,7 +304,7 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override; virtual bool operator==(const Type& _other) const override;
virtual unsigned getCalldataEncodedSize() const override; virtual unsigned getCalldataEncodedSize(bool _padded) const override;
virtual bool isDynamicallySized() const { return m_hasDynamicLength; } virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
virtual u256 getStorageSize() const override; virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() const override; virtual unsigned getSizeOnStack() const override;

12
test/SolidityABIJSON.cpp

@ -20,7 +20,7 @@
* Unit tests for the solidity compiler JSON Interface output. * Unit tests for the solidity compiler JSON Interface output.
*/ */
#include <boost/test/unit_test.hpp> #include "TestHelper.h"
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <json/json.h> #include <json/json.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
@ -39,15 +39,7 @@ public:
void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString)
{ {
try ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse(_code), "Parsing contract failed");
{
m_compilerStack.parse(_code);
}
catch(boost::exception const& _e)
{
auto msg = std::string("Parsing contract failed with: ") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
std::string generatedInterfaceString = m_compilerStack.getMetadata("", DocumentationType::ABIInterface); std::string generatedInterfaceString = m_compilerStack.getMetadata("", DocumentationType::ABIInterface);
Json::Value generatedInterface; Json::Value generatedInterface;
m_reader.parse(generatedInterfaceString, generatedInterface); m_reader.parse(generatedInterfaceString, generatedInterface);

99
test/SolidityEndToEndTest.cpp

@ -3008,6 +3008,105 @@ BOOST_AUTO_TEST_CASE(bytes_index_access)
BOOST_CHECK(callContractFunction("storageWrite()") == encodeArgs(0x193)); BOOST_CHECK(callContractFunction("storageWrite()") == encodeArgs(0x193));
} }
BOOST_AUTO_TEST_CASE(array_copy_calldata_storage)
{
char const* sourceCode = R"(
contract c {
uint[9] m_data;
uint[] m_data_dyn;
uint8[][] m_byte_data;
function store(uint[9] a, uint8[3][] b) external returns (uint8) {
m_data = a;
m_data_dyn = a;
m_byte_data = b;
return b[3][1]; // note that access and declaration are reversed to each other
}
function retrieve() returns (uint a, uint b, uint c, uint d, uint e, uint f, uint g) {
a = m_data.length;
b = m_data[7];
c = m_data_dyn.length;
d = m_data_dyn[7];
e = m_byte_data.length;
f = m_byte_data[3].length;
g = m_byte_data[3][1];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs(
21, 22, 23, 24, 25, 26, 27, 28, 29, // a
4, // size of b
1, 2, 3, // b[0]
11, 12, 13, // b[1]
21, 22, 23, // b[2]
31, 32, 33 // b[3]
)) == encodeArgs(32));
BOOST_CHECK(callContractFunction("retrieve()") == encodeArgs(
9, 28, 9, 28,
4, 3, 32));
}
BOOST_AUTO_TEST_CASE(array_copy_nested_array)
{
char const* sourceCode = R"(
contract c {
uint[4][] a;
uint[5][] b;
uint[][] c;
function test(uint[2][] d) external returns (uint) {
a = d;
b = a;
c = b;
return c[1][1] | c[1][2] | c[1][3] | c[1][4];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test(uint256[2][])", encodeArgs(
3,
7, 8,
9, 10,
11, 12
)) == encodeArgs(10));
}
BOOST_AUTO_TEST_CASE(array_copy_including_mapping)
{
char const* sourceCode = R"(
contract c {
mapping(uint=>uint)[90][] large;
mapping(uint=>uint)[3][] small;
function test() returns (uint r) {
large.length = small.length = 7;
large[3][2][0] = 2;
large[1] = large[3];
small[3][2][0] = 2;
small[1] = small[2];
r = ((
small[3][2][0] * 0x100 |
small[1][2][0]) * 0x100 |
large[3][2][0]) * 0x100 |
large[1][2][0];
delete small;
delete large;
}
function clear() returns (uint r) {
large.length = small.length = 7;
small[3][2][0] = 0;
large[3][2][0] = 0;
small.length = large.length = 0;
return 7;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(0x02000200));
// storage is not empty because we cannot delete the mappings
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == encodeArgs(7));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base) BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

10
test/SolidityExpressionCompiler.cpp

@ -30,7 +30,7 @@
#include <libsolidity/CompilerContext.h> #include <libsolidity/CompilerContext.h>
#include <libsolidity/ExpressionCompiler.h> #include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <boost/test/unit_test.hpp> #include "TestHelper.h"
using namespace std; using namespace std;
@ -72,8 +72,8 @@ private:
Expression* m_expression; Expression* m_expression;
}; };
Declaration const& resolveDeclaration(vector<string> const& _namespacedName, Declaration const& resolveDeclaration(
NameAndTypeResolver const& _resolver) vector<string> const& _namespacedName, NameAndTypeResolver const& _resolver)
{ {
Declaration const* declaration = nullptr; Declaration const* declaration = nullptr;
// bracers are required, cause msvc couldnt handle this macro in for statement // bracers are required, cause msvc couldnt handle this macro in for statement
@ -112,13 +112,13 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes()) for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{ {
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); ETH_TEST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract), "Resolving names failed");
inheritanceHierarchy = vector<ContractDefinition const*>(1, contract); inheritanceHierarchy = vector<ContractDefinition const*>(1, contract);
} }
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes()) for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{ {
BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract)); ETH_TEST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract), "Checking type Requirements failed");
} }
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes()) for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))

6
test/SolidityInterface.cpp

@ -20,7 +20,7 @@
* Unit tests for generating source interfaces for Solidity contracts. * Unit tests for generating source interfaces for Solidity contracts.
*/ */
#include <boost/test/unit_test.hpp> #include "TestHelper.h"
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
@ -42,9 +42,9 @@ public:
ContractDefinition const& checkInterface(string const& _code, string const& _contractName = "") ContractDefinition const& checkInterface(string const& _code, string const& _contractName = "")
{ {
m_code = _code; m_code = _code;
BOOST_REQUIRE_NO_THROW(m_compilerStack.parse(_code)); ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse(_code), "Parsing failed");
m_interface = m_compilerStack.getMetadata("", DocumentationType::ABISolidityInterface); m_interface = m_compilerStack.getMetadata("", DocumentationType::ABISolidityInterface);
BOOST_REQUIRE_NO_THROW(m_reCompiler.parse(m_interface)); ETH_TEST_REQUIRE_NO_THROW(m_reCompiler.parse(m_interface), "Interface parsing failed");
return m_reCompiler.getContractDefinition(_contractName); return m_reCompiler.getContractDefinition(_contractName);
} }

137
test/SolidityNameAndTypeResolution.cpp

@ -28,7 +28,7 @@
#include <libsolidity/Parser.h> #include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h> #include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp> #include "TestHelper.h"
using namespace std; using namespace std;
@ -58,30 +58,6 @@ ASTPointer<SourceUnit> parseTextAndResolveNames(std::string const& _source)
return sourceUnit; return sourceUnit;
} }
ASTPointer<SourceUnit> parseTextAndResolveNamesWithChecks(std::string const& _source)
{
Parser parser;
ASTPointer<SourceUnit> sourceUnit;
try
{
sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
NameAndTypeResolver resolver({});
resolver.registerDeclarations(*sourceUnit);
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
resolver.resolveNamesAndTypes(*contract);
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
resolver.checkTypeRequirements(*contract);
}
catch(boost::exception const& _e)
{
auto msg = std::string("Parsing text and resolving names failed with: \n") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
return sourceUnit;
}
static ContractDefinition const* retrieveContract(ASTPointer<SourceUnit> _source, unsigned index) static ContractDefinition const* retrieveContract(ASTPointer<SourceUnit> _source, unsigned index)
{ {
ContractDefinition* contract; ContractDefinition* contract;
@ -109,7 +85,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
" uint256 stateVariable1;\n" " uint256 stateVariable1;\n"
" function fun(uint256 arg1) { var x; uint256 y; }" " function fun(uint256 arg1) { var x; uint256 y; }"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(double_stateVariable_declaration) BOOST_AUTO_TEST_CASE(double_stateVariable_declaration)
@ -144,7 +120,7 @@ BOOST_AUTO_TEST_CASE(name_shadowing)
" uint256 variable;\n" " uint256 variable;\n"
" function f() { uint32 variable ; }" " function f() { uint32 variable ; }"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(name_references) BOOST_AUTO_TEST_CASE(name_references)
@ -153,7 +129,7 @@ BOOST_AUTO_TEST_CASE(name_references)
" uint256 variable;\n" " uint256 variable;\n"
" function f(uint256 arg) returns (uint out) { f(variable); test; out; }" " function f(uint256 arg) returns (uint out) { f(variable); test; out; }"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(undeclared_name) BOOST_AUTO_TEST_CASE(undeclared_name)
@ -171,7 +147,7 @@ BOOST_AUTO_TEST_CASE(reference_to_later_declaration)
" function g() { f(); }" " function g() { f(); }"
" function f() { }" " function f() { }"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(struct_definition_directly_recursive) BOOST_AUTO_TEST_CASE(struct_definition_directly_recursive)
@ -209,7 +185,7 @@ BOOST_AUTO_TEST_CASE(struct_definition_recursion_via_mapping)
" mapping(uint => MyStructName1) x;\n" " mapping(uint => MyStructName1) x;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(type_inference_smoke_test) BOOST_AUTO_TEST_CASE(type_inference_smoke_test)
@ -217,7 +193,7 @@ BOOST_AUTO_TEST_CASE(type_inference_smoke_test)
char const* text = "contract test {\n" char const* text = "contract test {\n"
" function f(uint256 arg1, uint32 arg2) returns (bool ret) { var x = arg1 + arg2 == 8; ret = x; }" " function f(uint256 arg1, uint32 arg2) returns (bool ret) { var x = arg1 + arg2 == 8; ret = x; }"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(type_checking_return) BOOST_AUTO_TEST_CASE(type_checking_return)
@ -225,7 +201,7 @@ BOOST_AUTO_TEST_CASE(type_checking_return)
char const* text = "contract test {\n" char const* text = "contract test {\n"
" function f() returns (bool r) { return 1 >= 2; }" " function f() returns (bool r) { return 1 >= 2; }"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(type_checking_return_wrong_number) BOOST_AUTO_TEST_CASE(type_checking_return_wrong_number)
@ -250,7 +226,7 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call)
" function f() returns (bool r) { return g(12, true) == 3; }\n" " function f() returns (bool r) { return g(12, true) == 3; }\n"
" function g(uint256 a, bool b) returns (uint256 r) { }\n" " function g(uint256 a, bool b) returns (uint256 r) { }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison) BOOST_AUTO_TEST_CASE(type_conversion_for_comparison)
@ -258,7 +234,7 @@ BOOST_AUTO_TEST_CASE(type_conversion_for_comparison)
char const* text = "contract test {\n" char const* text = "contract test {\n"
" function f() { uint32(2) == int64(2); }" " function f() { uint32(2) == int64(2); }"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid) BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid)
@ -274,7 +250,7 @@ BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion)
char const* text = "contract test {\n" char const* text = "contract test {\n"
" function f() returns (int256 r) { var x = int256(uint32(2)); return x; }" " function f() returns (int256 r) { var x = int256(uint32(2)); return x; }"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(large_string_literal) BOOST_AUTO_TEST_CASE(large_string_literal)
@ -292,7 +268,7 @@ BOOST_AUTO_TEST_CASE(balance)
" uint256 x = address(0).balance;\n" " uint256 x = address(0).balance;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(balance_invalid) BOOST_AUTO_TEST_CASE(balance_invalid)
@ -332,7 +308,7 @@ BOOST_AUTO_TEST_CASE(assignment_to_struct)
" data = a;\n" " data = a;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(returns_in_constructor) BOOST_AUTO_TEST_CASE(returns_in_constructor)
@ -356,7 +332,7 @@ BOOST_AUTO_TEST_CASE(forward_function_reference)
" if (First(2).fun() == true) return 1;\n" " if (First(2).fun() == true) return 1;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(comparison_bitop_precedence) BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
@ -366,7 +342,7 @@ BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
" return 1 & 2 == 8 & 9 && 1 ^ 2 < 4 | 6;\n" " return 1 & 2 == 8 & 9 && 1 ^ 2 < 4 | 6;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(function_canonical_signature) BOOST_AUTO_TEST_CASE(function_canonical_signature)
@ -423,7 +399,7 @@ BOOST_AUTO_TEST_CASE(inheritance_basic)
function f() { baseMember = 7; } function f() { baseMember = 7; }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(inheritance_diamond_basic) BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
@ -436,7 +412,7 @@ BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
function g() { f(); rootFunction(); } function g() { f(); rootFunction(); }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(cyclic_inheritance) BOOST_AUTO_TEST_CASE(cyclic_inheritance)
@ -492,7 +468,7 @@ BOOST_AUTO_TEST_CASE(complex_inheritance)
contract B { function f() {} function g() returns (uint8 r) {} } contract B { function f() {} function g() returns (uint8 r) {} }
contract C is A, B { } contract C is A, B { }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(constructor_visibility) BOOST_AUTO_TEST_CASE(constructor_visibility)
@ -502,7 +478,7 @@ BOOST_AUTO_TEST_CASE(constructor_visibility)
contract A { function A() { } } contract A { function A() { } }
contract B is A { function f() { A x = A(0); } } contract B is A { function f() { A x = A(0); } }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(overriding_constructor) BOOST_AUTO_TEST_CASE(overriding_constructor)
@ -512,7 +488,7 @@ BOOST_AUTO_TEST_CASE(overriding_constructor)
contract A { function A() { } } contract A { function A() { } }
contract B is A { function A() returns (uint8 r) {} } contract B is A { function A() returns (uint8 r) {} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments) BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments)
@ -541,7 +517,7 @@ BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)
function f() { A a = B(1); } function f() { A a = B(1); }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion) BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
@ -564,7 +540,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation)
modifier mod2(string7 a) { while (a == "1234567") _ } modifier mod2(string7 a) { while (a == "1234567") _ }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(invalid_function_modifier_type) BOOST_AUTO_TEST_CASE(invalid_function_modifier_type)
@ -587,7 +563,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_parameters)
modifier mod2(string7 a) { while (a == "1234567") _ } modifier mod2(string7 a) { while (a == "1234567") _ }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables) BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
@ -598,7 +574,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
modifier mod(uint a) { if (a > 0) _ } modifier mod(uint a) { if (a > 0) _ }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(legal_modifier_override) BOOST_AUTO_TEST_CASE(legal_modifier_override)
@ -607,7 +583,7 @@ BOOST_AUTO_TEST_CASE(legal_modifier_override)
contract A { modifier mod(uint a) {} } contract A { modifier mod(uint a) {} }
contract B is A { modifier mod(uint a) {} } contract B is A { modifier mod(uint a) {} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(illegal_modifier_override) BOOST_AUTO_TEST_CASE(illegal_modifier_override)
@ -661,7 +637,7 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
ASTPointer<SourceUnit> source; ASTPointer<SourceUnit> source;
ContractDefinition const* contract; ContractDefinition const* contract;
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(source = parseTextAndResolveNames(text), "Parsing and Resolving names failed");
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr); BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()"); FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()");
BOOST_REQUIRE(function && function->hasDeclaration()); BOOST_REQUIRE(function && function->hasDeclaration());
@ -711,7 +687,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
ASTPointer<SourceUnit> source; ASTPointer<SourceUnit> source;
ContractDefinition const* contract; ContractDefinition const* contract;
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(source = parseTextAndResolveNames(text), "Parsing and Resolving names failed");
BOOST_CHECK((contract = retrieveContract(source, 0)) != nullptr); BOOST_CHECK((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function; FunctionTypePointer function;
function = retrieveFunctionBySignature(contract, "foo()"); function = retrieveFunctionBySignature(contract, "foo()");
@ -729,7 +705,7 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
"contract Child is Parent{\n" "contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n" " function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member) BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
@ -740,7 +716,7 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
"contract Child is Parent{\n" "contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n" " function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class1) BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class1)
@ -780,7 +756,7 @@ BOOST_AUTO_TEST_CASE(fallback_function)
function() { x = 2; } function() { x = 2; }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(fallback_function_with_arguments) BOOST_AUTO_TEST_CASE(fallback_function_with_arguments)
@ -817,7 +793,7 @@ BOOST_AUTO_TEST_CASE(fallback_function_inheritance)
function() { x = 2; } function() { x = 2; }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(event) BOOST_AUTO_TEST_CASE(event)
@ -827,7 +803,7 @@ BOOST_AUTO_TEST_CASE(event)
event e(uint indexed a, string3 indexed s, bool indexed b); event e(uint indexed a, string3 indexed s, bool indexed b);
function f() { e(2, "abc", true); } function f() { e(2, "abc", true); }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(event_too_many_indexed) BOOST_AUTO_TEST_CASE(event_too_many_indexed)
@ -847,7 +823,7 @@ BOOST_AUTO_TEST_CASE(event_call)
event e(uint a, string3 indexed s, bool indexed b); event e(uint a, string3 indexed s, bool indexed b);
function f() { e(2, "abc", true); } function f() { e(2, "abc", true); }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(event_inheritance) BOOST_AUTO_TEST_CASE(event_inheritance)
@ -859,7 +835,7 @@ BOOST_AUTO_TEST_CASE(event_inheritance)
contract c is base { contract c is base {
function f() { e(2, "abc", true); } function f() { e(2, "abc", true); }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(multiple_events_argument_clash) BOOST_AUTO_TEST_CASE(multiple_events_argument_clash)
@ -869,7 +845,7 @@ BOOST_AUTO_TEST_CASE(multiple_events_argument_clash)
event e1(uint a, uint e1, uint e2); event e1(uint a, uint e1, uint e2);
event e2(uint a, uint e1, uint e2); event e2(uint a, uint e1, uint e2);
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(access_to_default_function_visibility) BOOST_AUTO_TEST_CASE(access_to_default_function_visibility)
@ -881,7 +857,7 @@ BOOST_AUTO_TEST_CASE(access_to_default_function_visibility)
contract d { contract d {
function g() { c(0).f(); } function g() { c(0).f(); }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(access_to_internal_function) BOOST_AUTO_TEST_CASE(access_to_internal_function)
@ -917,7 +893,7 @@ BOOST_AUTO_TEST_CASE(access_to_internal_state_variable)
contract d { contract d {
function g() { c(0).a(); } function g() { c(0).a(); }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(error_count_in_named_args) BOOST_AUTO_TEST_CASE(error_count_in_named_args)
@ -963,7 +939,7 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter)
function f(uint){ function f(uint){
} }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(empty_name_return_parameter) BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
@ -973,7 +949,7 @@ BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
function f() returns(bool){ function f() returns(bool){
} }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
@ -984,7 +960,7 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
return k; return k;
} }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(empty_name_return_parameter_with_named_one) BOOST_AUTO_TEST_CASE(empty_name_return_parameter_with_named_one)
@ -1014,7 +990,8 @@ BOOST_AUTO_TEST_CASE(overflow_caused_by_ether_units)
} }
uint256 a; uint256 a;
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCodeFine)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCodeFine),
"Parsing and Resolving names failed");
char const* sourceCode = R"( char const* sourceCode = R"(
contract c { contract c {
function c () function c ()
@ -1056,7 +1033,7 @@ BOOST_AUTO_TEST_CASE(enum_member_access)
ActionChoices choices; ActionChoices choices;
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(enum_invalid_member_access) BOOST_AUTO_TEST_CASE(enum_invalid_member_access)
@ -1088,7 +1065,7 @@ BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay)
uint64 b; uint64 b;
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay) BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay)
@ -1105,7 +1082,7 @@ BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay)
ActionChoices b; ActionChoices b;
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay) BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay)
@ -1225,7 +1202,7 @@ BOOST_AUTO_TEST_CASE(test_for_bug_override_function_with_bytearray_type)
function f(bytes _a) external returns (uint256 r) {r = 42;} function f(bytes _a) external returns (uint256 r) {r = 42;}
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(sourceCode)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode), "Parsing and Name Resolving failed");
} }
BOOST_AUTO_TEST_CASE(array_with_nonconstant_length) BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
@ -1267,7 +1244,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_conversion_possible)
uint8[] b; uint8[] b;
function f() { a = b; } function f() { a = b; }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic) BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic)
@ -1278,7 +1255,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic)
uint8[80] b; uint8[80] b;
function f() { a = b; } function f() { a = b; }
})"; })";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
} }
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static) BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static)
@ -1292,6 +1269,24 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
} }
BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_int)
{
char const* text = R"(
contract c {
uint8 a = 1000;
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_string)
{
char const* text = R"(
contract c {
uint a = "abc";
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

12
test/SolidityNatspecJSON.cpp

@ -20,7 +20,7 @@
* Unit tests for the solidity compiler JSON Interface output. * Unit tests for the solidity compiler JSON Interface output.
*/ */
#include <boost/test/unit_test.hpp> #include "TestHelper.h"
#include <json/json.h> #include <json/json.h>
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
@ -43,15 +43,7 @@ public:
bool _userDocumentation) bool _userDocumentation)
{ {
std::string generatedDocumentationString; std::string generatedDocumentationString;
try ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse(_code), "Parsing failed");
{
m_compilerStack.parse(_code);
}
catch(boost::exception const& _e)
{
auto msg = std::string("Parsing contract failed with: ") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
if (_userDocumentation) if (_userDocumentation)
generatedDocumentationString = m_compilerStack.getMetadata("", DocumentationType::NatspecUser); generatedDocumentationString = m_compilerStack.getMetadata("", DocumentationType::NatspecUser);

146
test/SolidityParser.cpp

@ -26,7 +26,7 @@
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h> #include <libsolidity/Parser.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp> #include "TestHelper.h"
using namespace std; using namespace std;
@ -50,22 +50,6 @@ ASTPointer<ContractDefinition> parseText(std::string const& _source)
return ASTPointer<ContractDefinition>(); return ASTPointer<ContractDefinition>();
} }
ASTPointer<ContractDefinition> parseTextExplainError(std::string const& _source)
{
try
{
return parseText(_source);
}
catch (Exception const& exception)
{
// LTODO: Print the error in a kind of a better way?
// In absence of CompilerStack we can't use SourceReferenceFormatter
cout << "Exception while parsing: " << diagnostic_information(exception);
// rethrow to signal test failure
throw exception;
}
}
static void checkFunctionNatspec(ASTPointer<FunctionDefinition> _function, static void checkFunctionNatspec(ASTPointer<FunctionDefinition> _function,
std::string const& _expectedDoc) std::string const& _expectedDoc)
{ {
@ -84,7 +68,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
char const* text = "contract test {\n" char const* text = "contract test {\n"
" uint256 stateVariable1;\n" " uint256 stateVariable1;\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
} }
BOOST_AUTO_TEST_CASE(missing_variable_name_in_declaration) BOOST_AUTO_TEST_CASE(missing_variable_name_in_declaration)
@ -103,7 +87,7 @@ BOOST_AUTO_TEST_CASE(empty_function)
" returns (int id)\n" " returns (int id)\n"
" { }\n" " { }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
} }
BOOST_AUTO_TEST_CASE(no_function_params) BOOST_AUTO_TEST_CASE(no_function_params)
@ -112,7 +96,7 @@ BOOST_AUTO_TEST_CASE(no_function_params)
" uint256 stateVar;\n" " uint256 stateVar;\n"
" function functionName() {}\n" " function functionName() {}\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
} }
BOOST_AUTO_TEST_CASE(single_function_param) BOOST_AUTO_TEST_CASE(single_function_param)
@ -121,7 +105,7 @@ BOOST_AUTO_TEST_CASE(single_function_param)
" uint256 stateVar;\n" " uint256 stateVar;\n"
" function functionName(hash hashin) returns (hash hashout) {}\n" " function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
} }
BOOST_AUTO_TEST_CASE(missing_parameter_name_in_named_args) BOOST_AUTO_TEST_CASE(missing_parameter_name_in_named_args)
@ -151,9 +135,9 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation)
" /// This is a test function\n" " /// This is a test function\n"
" function functionName(hash hashin) returns (hash hashout) {}\n" " function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n"; "}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text)); ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions(); auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
checkFunctionNatspec(function, "This is a test function"); checkFunctionNatspec(function, "This is a test function");
} }
@ -166,9 +150,9 @@ BOOST_AUTO_TEST_CASE(function_normal_comments)
" // We won't see this comment\n" " // We won't see this comment\n"
" function functionName(hash hashin) returns (hash hashout) {}\n" " function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n"; "}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text)); ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions(); auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr,
"Should not have gotten a Natspecc comment for this function"); "Should not have gotten a Natspecc comment for this function");
} }
@ -188,20 +172,20 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
" /// This is test function 4\n" " /// This is test function 4\n"
" function functionName4(hash hashin) returns (hash hashout) {}\n" " function functionName4(hash hashin) returns (hash hashout) {}\n"
"}\n"; "}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text)); ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions(); auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
checkFunctionNatspec(function, "This is test function 1"); checkFunctionNatspec(function, "This is test function 1");
BOOST_REQUIRE_NO_THROW(function = functions.at(1)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(1), "Failed to retrieve function");
checkFunctionNatspec(function, "This is test function 2"); checkFunctionNatspec(function, "This is test function 2");
BOOST_REQUIRE_NO_THROW(function = functions.at(2)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(2), "Failed to retrieve function");
BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr,
"Should not have gotten natspec comment for functionName3()"); "Should not have gotten natspec comment for functionName3()");
BOOST_REQUIRE_NO_THROW(function = functions.at(3)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(3), "Failed to retrieve function");
checkFunctionNatspec(function, "This is test function 4"); checkFunctionNatspec(function, "This is test function 4");
} }
@ -215,10 +199,10 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation)
" /// and it has 2 lines\n" " /// and it has 2 lines\n"
" function functionName1(hash hashin) returns (hash hashout) {}\n" " function functionName1(hash hashin) returns (hash hashout) {}\n"
"}\n"; "}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text)); ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions(); auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
checkFunctionNatspec(function, "This is a test function\n" checkFunctionNatspec(function, "This is a test function\n"
" and it has 2 lines"); " and it has 2 lines");
} }
@ -240,13 +224,13 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
" /// and it has 2 lines\n" " /// and it has 2 lines\n"
" function fun(hash hashin) returns (hash hashout) {}\n" " function fun(hash hashin) returns (hash hashout) {}\n"
"}\n"; "}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text)); ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions(); auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
checkFunctionNatspec(function, "fun1 description"); checkFunctionNatspec(function, "fun1 description");
BOOST_REQUIRE_NO_THROW(function = functions.at(1)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(1), "Failed to retrieve function");
checkFunctionNatspec(function, "This is a test function\n" checkFunctionNatspec(function, "This is a test function\n"
" and it has 2 lines"); " and it has 2 lines");
} }
@ -266,10 +250,10 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature)
" string name = \"Solidity\";" " string name = \"Solidity\";"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text)); ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions(); auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
BOOST_CHECK_MESSAGE(!function->getDocumentation(), BOOST_CHECK_MESSAGE(!function->getDocumentation(),
"Shouldn't get natspec docstring for this function"); "Shouldn't get natspec docstring for this function");
} }
@ -289,10 +273,10 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature)
" string name = \"Solidity\";" " string name = \"Solidity\";"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text)); ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions(); auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0)); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
BOOST_CHECK_MESSAGE(!function->getDocumentation(), BOOST_CHECK_MESSAGE(!function->getDocumentation(),
"Shouldn't get natspec docstring for this function"); "Shouldn't get natspec docstring for this function");
} }
@ -306,7 +290,7 @@ BOOST_AUTO_TEST_CASE(struct_definition)
" uint256 count;\n" " uint256 count;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(mapping) BOOST_AUTO_TEST_CASE(mapping)
@ -314,7 +298,7 @@ BOOST_AUTO_TEST_CASE(mapping)
char const* text = "contract test {\n" char const* text = "contract test {\n"
" mapping(address => string) names;\n" " mapping(address => string) names;\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(mapping_in_struct) BOOST_AUTO_TEST_CASE(mapping_in_struct)
@ -326,7 +310,7 @@ BOOST_AUTO_TEST_CASE(mapping_in_struct)
" mapping(hash => test_struct) self_reference;\n" " mapping(hash => test_struct) self_reference;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct) BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
@ -337,7 +321,7 @@ BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
" mapping (uint64 => mapping (hash => uint)) complex_mapping;\n" " mapping (uint64 => mapping (hash => uint)) complex_mapping;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(variable_definition) BOOST_AUTO_TEST_CASE(variable_definition)
@ -350,7 +334,7 @@ BOOST_AUTO_TEST_CASE(variable_definition)
" customtype varname;\n" " customtype varname;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(variable_definition_with_initialization) BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
@ -364,7 +348,7 @@ BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
" customtype varname;\n" " customtype varname;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(variable_definition_in_function_parameter) BOOST_AUTO_TEST_CASE(variable_definition_in_function_parameter)
@ -408,7 +392,7 @@ BOOST_AUTO_TEST_CASE(operator_expression)
" uint256 x = (1 + 4) || false && (1 - 12) + -9;\n" " uint256 x = (1 + 4) || false && (1 - 12) + -9;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(complex_expression) BOOST_AUTO_TEST_CASE(complex_expression)
@ -418,7 +402,7 @@ BOOST_AUTO_TEST_CASE(complex_expression)
" uint256 x = (1 + 4).member(++67)[a/=9] || true;\n" " uint256 x = (1 + 4).member(++67)[a/=9] || true;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(exp_expression) BOOST_AUTO_TEST_CASE(exp_expression)
@ -429,7 +413,7 @@ BOOST_AUTO_TEST_CASE(exp_expression)
uint256 x = 3 ** a; uint256 x = 3 ** a;
} }
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(while_loop) BOOST_AUTO_TEST_CASE(while_loop)
@ -439,7 +423,7 @@ BOOST_AUTO_TEST_CASE(while_loop)
" while (true) { uint256 x = 1; break; continue; } x = 9;\n" " while (true) { uint256 x = 1; break; continue; } x = 9;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(for_loop_vardef_initexpr) BOOST_AUTO_TEST_CASE(for_loop_vardef_initexpr)
@ -450,7 +434,7 @@ BOOST_AUTO_TEST_CASE(for_loop_vardef_initexpr)
" { uint256 x = i; break; continue; }\n" " { uint256 x = i; break; continue; }\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(for_loop_simple_initexpr) BOOST_AUTO_TEST_CASE(for_loop_simple_initexpr)
@ -462,7 +446,7 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_initexpr)
" { uint256 x = i; break; continue; }\n" " { uint256 x = i; break; continue; }\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(for_loop_simple_noexpr) BOOST_AUTO_TEST_CASE(for_loop_simple_noexpr)
@ -474,7 +458,7 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_noexpr)
" { uint256 x = i; break; continue; }\n" " { uint256 x = i; break; continue; }\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(for_loop_single_stmt_body) BOOST_AUTO_TEST_CASE(for_loop_single_stmt_body)
@ -486,7 +470,7 @@ BOOST_AUTO_TEST_CASE(for_loop_single_stmt_body)
" continue;\n" " continue;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(if_statement) BOOST_AUTO_TEST_CASE(if_statement)
@ -496,7 +480,7 @@ BOOST_AUTO_TEST_CASE(if_statement)
" if (a >= 8) return 2; else { var b = 7; }\n" " if (a >= 8) return 2; else { var b = 7; }\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(else_if_statement) BOOST_AUTO_TEST_CASE(else_if_statement)
@ -506,7 +490,7 @@ BOOST_AUTO_TEST_CASE(else_if_statement)
" if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;\n" " if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion) BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
@ -518,7 +502,7 @@ BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
" uint64[](3);\n" " uint64[](3);\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(type_conversion_to_dynamic_array) BOOST_AUTO_TEST_CASE(type_conversion_to_dynamic_array)
@ -528,7 +512,7 @@ BOOST_AUTO_TEST_CASE(type_conversion_to_dynamic_array)
" var x = uint64[](3);\n" " var x = uint64[](3);\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(import_directive) BOOST_AUTO_TEST_CASE(import_directive)
@ -539,7 +523,7 @@ BOOST_AUTO_TEST_CASE(import_directive)
" uint64(2);\n" " uint64(2);\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(multiple_contracts) BOOST_AUTO_TEST_CASE(multiple_contracts)
@ -554,7 +538,7 @@ BOOST_AUTO_TEST_CASE(multiple_contracts)
" uint64(2);\n" " uint64(2);\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports) BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports)
@ -572,7 +556,7 @@ BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports)
" }\n" " }\n"
"}\n" "}\n"
"import \"ghi\";\n"; "import \"ghi\";\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(contract_inheritance) BOOST_AUTO_TEST_CASE(contract_inheritance)
@ -587,7 +571,7 @@ BOOST_AUTO_TEST_CASE(contract_inheritance)
" uint64(2);\n" " uint64(2);\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(contract_multiple_inheritance) BOOST_AUTO_TEST_CASE(contract_multiple_inheritance)
@ -602,7 +586,7 @@ BOOST_AUTO_TEST_CASE(contract_multiple_inheritance)
" uint64(2);\n" " uint64(2);\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments) BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments)
@ -617,7 +601,7 @@ BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments)
" uint64(2);\n" " uint64(2);\n"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(placeholder_in_function_context) BOOST_AUTO_TEST_CASE(placeholder_in_function_context)
@ -628,7 +612,7 @@ BOOST_AUTO_TEST_CASE(placeholder_in_function_context)
" return _ + 1;" " return _ + 1;"
" }\n" " }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(modifier) BOOST_AUTO_TEST_CASE(modifier)
@ -636,7 +620,7 @@ BOOST_AUTO_TEST_CASE(modifier)
char const* text = "contract c {\n" char const* text = "contract c {\n"
" modifier mod { if (msg.sender == 0) _ }\n" " modifier mod { if (msg.sender == 0) _ }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(modifier_arguments) BOOST_AUTO_TEST_CASE(modifier_arguments)
@ -644,7 +628,7 @@ BOOST_AUTO_TEST_CASE(modifier_arguments)
char const* text = "contract c {\n" char const* text = "contract c {\n"
" modifier mod(uint a) { if (msg.sender == a) _ }\n" " modifier mod(uint a) { if (msg.sender == a) _ }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(modifier_invocation) BOOST_AUTO_TEST_CASE(modifier_invocation)
@ -654,7 +638,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation)
" modifier mod2 { if (msg.sender == 2) _ }\n" " modifier mod2 { if (msg.sender == 2) _ }\n"
" function f() mod1(7) mod2 { }\n" " function f() mod1(7) mod2 { }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(fallback_function) BOOST_AUTO_TEST_CASE(fallback_function)
@ -662,7 +646,7 @@ BOOST_AUTO_TEST_CASE(fallback_function)
char const* text = "contract c {\n" char const* text = "contract c {\n"
" function() { }\n" " function() { }\n"
"}\n"; "}\n";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(event) BOOST_AUTO_TEST_CASE(event)
@ -671,7 +655,7 @@ BOOST_AUTO_TEST_CASE(event)
contract c { contract c {
event e(); event e();
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(event_arguments) BOOST_AUTO_TEST_CASE(event_arguments)
@ -680,7 +664,7 @@ BOOST_AUTO_TEST_CASE(event_arguments)
contract c { contract c {
event e(uint a, string32 s); event e(uint a, string32 s);
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(event_arguments_indexed) BOOST_AUTO_TEST_CASE(event_arguments_indexed)
@ -689,7 +673,7 @@ BOOST_AUTO_TEST_CASE(event_arguments_indexed)
contract c { contract c {
event e(uint a, string32 indexed s, bool indexed b); event e(uint a, string32 indexed s, bool indexed b);
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(visibility_specifiers) BOOST_AUTO_TEST_CASE(visibility_specifiers)
@ -705,7 +689,7 @@ BOOST_AUTO_TEST_CASE(visibility_specifiers)
function f_public() public {} function f_public() public {}
function f_internal() internal {} function f_internal() internal {}
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers) BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
@ -733,7 +717,7 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
uint256 c; uint256 c;
uint256 d; uint256 d;
})"; })";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expressions) BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expressions)
@ -746,7 +730,7 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expression
} }
uint256 a; uint256 a;
})"; })";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(enum_valid_declaration) BOOST_AUTO_TEST_CASE(enum_valid_declaration)
@ -760,7 +744,7 @@ BOOST_AUTO_TEST_CASE(enum_valid_declaration)
} }
uint256 a; uint256 a;
})"; })";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(empty_enum_declaration) BOOST_AUTO_TEST_CASE(empty_enum_declaration)
@ -769,7 +753,7 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration)
contract c { contract c {
enum foo { } enum foo { }
})"; })";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(malformed_enum_declaration) BOOST_AUTO_TEST_CASE(malformed_enum_declaration)
@ -787,7 +771,7 @@ BOOST_AUTO_TEST_CASE(external_function)
contract c { contract c {
function x() external {} function x() external {}
})"; })";
BOOST_CHECK_NO_THROW(parseTextExplainError(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(external_variable) BOOST_AUTO_TEST_CASE(external_variable)
@ -808,7 +792,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_storage)
struct x { uint[2**20] b; y[0] c; } struct x { uint[2**20] b; y[0] c; }
struct y { uint d; mapping(uint=>x)[] e; } struct y { uint d; mapping(uint=>x)[] e; }
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(arrays_in_events) BOOST_AUTO_TEST_CASE(arrays_in_events)
@ -817,7 +801,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_events)
contract c { contract c {
event e(uint[10] a, string7[8] indexed b, c[3] x); event e(uint[10] a, string7[8] indexed b, c[3] x);
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(arrays_in_expressions) BOOST_AUTO_TEST_CASE(arrays_in_expressions)
@ -826,7 +810,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_expressions)
contract c { contract c {
function f() { c[10] a = 7; uint8[10 * 2] x; } function f() { c[10] a = 7; uint8[10 * 2] x; }
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_CASE(multi_arrays) BOOST_AUTO_TEST_CASE(multi_arrays)
@ -835,7 +819,7 @@ BOOST_AUTO_TEST_CASE(multi_arrays)
contract c { contract c {
mapping(uint => mapping(uint => int8)[8][][9])[] x; mapping(uint => mapping(uint => int8)[8][][9])[] x;
})"; })";
BOOST_CHECK_NO_THROW(parseText(text)); ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

37
test/TestHelper.h

@ -44,6 +44,43 @@ void connectClients(Client& c1, Client& c2);
namespace test namespace test
{ {
/// Make sure that no Exception is thrown during testing. If one is thrown show its info and fail the test.
/// Our version of BOOST_REQUIRE_NO_THROW()
/// @param _expression The expression for which to make sure no exceptions are thrown
/// @param _message A message to act as a prefix to the expression's error information
#define ETH_TEST_REQUIRE_NO_THROW(_expression, _message) \
do \
{ \
try \
{ \
_expression; \
} \
catch (boost::exception const& _e) \
{ \
auto msg = std::string(_message"\n") + boost::diagnostic_information(_e); \
BOOST_FAIL(msg); \
} \
} while (0)
/// Check if an Exception is thrown during testing. If one is thrown show its info and continue the test
/// Our version of BOOST_CHECK_NO_THROW()
/// @param _expression The expression for which to make sure no exceptions are thrown
/// @param _message A message to act as a prefix to the expression's error information
#define ETH_TEST_CHECK_NO_THROW(_expression, _message) \
do \
{ \
try \
{ \
_expression; \
} \
catch (boost::exception const& _e) \
{ \
auto msg = std::string(_message"\n") + boost::diagnostic_information(_e); \
BOOST_MESSAGE(msg); \
} \
} while (0)
class ImportTest class ImportTest
{ {
public: public:

14
test/solidityExecutionFramework.h

@ -25,7 +25,7 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <boost/test/unit_test.hpp> #include "TestHelper.h"
#include <libethereum/State.h> #include <libethereum/State.h>
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
@ -46,16 +46,8 @@ public:
bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "")
{ {
dev::solidity::CompilerStack compiler(m_addStandardSources); dev::solidity::CompilerStack compiler(m_addStandardSources);
try
{
compiler.addSource("", _sourceCode); compiler.addSource("", _sourceCode);
compiler.compile(m_optimize); ETH_TEST_REQUIRE_NO_THROW(compiler.compile(m_optimize), "Compiling contract failed");
}
catch(boost::exception const& _e)
{
auto msg = std::string("Compiling contract failed with: ") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
bytes code = compiler.getBytecode(_contractName); bytes code = compiler.getBytecode(_contractName);
sendMessage(code, true, _value); sendMessage(code, true, _value);
@ -178,7 +170,7 @@ protected:
Address m_contractAddress; Address m_contractAddress;
eth::State m_state; eth::State m_state;
u256 const m_gasPrice = 100 * eth::szabo; u256 const m_gasPrice = 100 * eth::szabo;
u256 const m_gas = 1000000; u256 const m_gas = 100000000;
bytes m_output; bytes m_output;
eth::LogEntries m_logs; eth::LogEntries m_logs;
}; };

Loading…
Cancel
Save