From c6c8a1ceebb4fd8b57df640c882c84b358a87675 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 30 Jan 2015 16:06:56 +0100 Subject: [PATCH 1/4] Adding mapping treatment to FunctionType Plus a TypeResolution test for it --- libsolidity/Types.cpp | 23 ++++++++++++++++++----- test/SolidityNameAndTypeResolution.cpp | 10 +++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index ab401332a..7fa4561e3 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -621,12 +621,25 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal FunctionType::FunctionType(VariableDeclaration const& _varDecl): m_location(Location::EXTERNAL), m_isConstant(true), m_declaration(&_varDecl) { - TypePointers params({}); - vector paramNames({}); - TypePointers retParams({_varDecl.getType()}); - vector retParamNames({ _varDecl.getName()}); - // for now, no input parameters LTODO: change for some things like mapping + TypePointers params; + vector paramNames; + TypePointers retParams; + vector retParamNames; + TypePointer varDeclType = _varDecl.getType(); + auto mappingType = dynamic_cast(varDeclType.get()); + if (mappingType!= nullptr) + { + params.push_back(mappingType->getKeyType()); + paramNames.push_back(mappingType->getKeyType()->toString()); + retParams.push_back(mappingType->getValueType()); + retParamNames.push_back(mappingType->getValueType()->toString()); + } + else // elelemntary type + { + retParams.push_back(varDeclType); + retParamNames.push_back(_varDecl.getName()); + } swap(params, m_parameterTypes); swap(paramNames, m_parameterNames); swap(retParams, m_returnParameterTypes); diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index b9a7140f7..df0e07e1d 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -637,6 +637,7 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors) " uint64(2);\n" " }\n" "uint256 foo;\n" + "mapping(uint=>string4) map;\n" "}\n"; ASTPointer source; @@ -644,10 +645,17 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors) BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text)); BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr); FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()"); - BOOST_REQUIRE(function->hasDeclaration()); + BOOST_REQUIRE(function && function->hasDeclaration()); auto returnParams = function->getReturnParameterTypeNames(); BOOST_CHECK_EQUAL(returnParams.at(0), "uint256"); BOOST_CHECK(function->isConstant()); + function = retrieveFunctionBySignature(contract, "map(uint256)"); + BOOST_REQUIRE(function && function->hasDeclaration()); + auto Params = function->getParameterTypeNames(); + BOOST_CHECK_EQUAL(returnParams.at(0), "uint256"); + returnParams = function->getReturnParameterTypeNames(); + BOOST_CHECK_EQUAL(returnParams.at(0), "string4"); + BOOST_CHECK(function->isConstant()); } BOOST_AUTO_TEST_CASE(function_clash_with_state_variable_accessor) From 4795991f2abadff12d80855ee82dd25c9ffaa0c3 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 1 Feb 2015 02:41:14 +0100 Subject: [PATCH 2/4] Code generation for mapping state variable accessor - Work in progress --- libsolidity/Compiler.cpp | 4 -- libsolidity/ExpressionCompiler.cpp | 75 ++++++++++++++++++++++++++---- libsolidity/ExpressionCompiler.h | 4 ++ test/SolidityEndToEndTest.cpp | 18 +++++++ 4 files changed, 89 insertions(+), 12 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 3c46d4552..389f826b7 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -240,10 +240,6 @@ bool Compiler::visit(VariableDeclaration const& _variableDeclaration) m_context << m_context.getFunctionEntryLabel(_variableDeclaration); ExpressionCompiler::appendStateVariableAccessor(m_context, _variableDeclaration); - unsigned sizeOnStack = _variableDeclaration.getType()->getSizeOnStack(); - solAssert(sizeOnStack <= 15, "Stack too deep."); - m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP; - return false; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 7d58ea2e2..edd04256f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -823,26 +823,85 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ return length; } -unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, - Expression const& _expression, unsigned _memoryOffset) +unsigned ExpressionCompiler::appendTypeCopyToMemory(Type const& _expectedType, TypePointer const& _type, + Location const& _location, unsigned _memoryOffset) { - _expression.accept(*this); - appendTypeConversion(*_expression.getType(), _expectedType, true); + appendTypeConversion(*_type, _expectedType, true); unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); if (c_numBytes == 0 || c_numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_sourceLocation(_location) << errinfo_comment("Type " + _expectedType.toString() + " not yet supported.")); bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING; bool const c_padToWords = true; return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords); } +unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, + Expression const& _expression, + unsigned _memoryOffset) +{ + _expression.accept(*this); + return appendTypeCopyToMemory(_expectedType, _expression.getType(), _expression.getLocation(), _memoryOffset); +} + void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { - m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType()); - solAssert(m_currentLValue.isInStorage(), ""); - m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true); + auto mappingType = dynamic_cast(_varDecl.getType().get()); + unsigned sizeOnStack; + if (mappingType != nullptr) + { + // this copies from Compiler::visit(FunctionDefinition..) for argument reading + unsigned parameterSize = mappingType->getKeyType()->getSizeOnStack(); + m_context.adjustStackOffset(parameterSize); + m_context.addVariable(_varDecl, parameterSize); + // this copies from ExpressionCompiler::visit(IndexAccess .. ) for mapping access + TypePointer const& keyType = mappingType->getKeyType(); + unsigned length = appendTypeCopyToMemory(*keyType, mappingType->getValueType(), Location()); + solAssert(length == 32, "Mapping key has to take 32 bytes in memory (for now)."); + // @todo move this once we actually use memory + length += CompilerUtils(m_context).storeInMemory(length); + m_context << u256(length) << u256(0) << eth::Instruction::SHA3; + + m_currentLValue = LValue(m_context, LValue::STORAGE, *mappingType->getValueType()); + m_currentLValue.retrieveValue(mappingType->getValueType(), Location(), true); + + unsigned const c_argumentsSize = keyType->getSizeOnStack(); + unsigned const c_returnValuesSize = mappingType->getValueType()->getSizeOnStack(); + unsigned const c_localVariablesSize = 0; + + vector stackLayout; + stackLayout.push_back(c_returnValuesSize); // target of return address + stackLayout += vector(c_argumentsSize, -1); // discard all arguments + for (unsigned i = 0; i < c_returnValuesSize; ++i) + stackLayout.push_back(i); + stackLayout += vector(c_localVariablesSize, -1); + + while (stackLayout.back() != int(stackLayout.size() - 1)) + if (stackLayout.back() < 0) + { + m_context << eth::Instruction::POP; + stackLayout.pop_back(); + } + else + { + m_context << eth::swapInstruction(stackLayout.size() - stackLayout.back() - 1); + swap(stackLayout[stackLayout.back()], stackLayout.back()); + } + //@todo assert that everything is in place now + + m_context << eth::Instruction::JUMP; + } + else + { + m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType()); + solAssert(m_currentLValue.isInStorage(), ""); + m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true); + sizeOnStack = _varDecl.getType()->getSizeOnStack(); + solAssert(sizeOnStack <= 15, "Stack too deep."); + m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP; + } + } ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index caecbfe8d..d93ab28ed 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -97,6 +97,10 @@ private: unsigned appendArgumentCopyToMemory(TypePointers const& _types, std::vector> const& _arguments, unsigned _memoryOffset = 0); + /// Appends code that copies a type to memory. + /// @returns the number of bytes copied to memory + unsigned appendTypeCopyToMemory(Type const& _expectedType, TypePointer const& _type, + Location const& _location, unsigned _memoryOffset = 0); /// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 7edc250c8..63a8ebcd3 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -919,6 +919,24 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors) BOOST_CHECK(callContractFunction("super_secret_data()") == bytes()); } +BOOST_AUTO_TEST_CASE(complex_accessors) +{ + char const* sourceCode = "contract test {\n" + " mapping(uint256 => string4) to_string_map;\n" + " mapping(uint256 => bool) to_bool_map;\n" + " mapping(uint256 => uint256) to_uint_map;\n" + " function test() {\n" + " to_string_map[42] = \"24\";\n" + " to_bool_map[42] = false;\n" + " to_uint_map[42] = 12;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("to_string_map(uint256)", 42) == encodeArgs("24")); + BOOST_CHECK(callContractFunction("to_bool_map(uint256)", 42) == encodeArgs(false)); + BOOST_CHECK(callContractFunction("to_uint_map(uint256)", 42) == encodeArgs(12)); +} + BOOST_AUTO_TEST_CASE(balance) { char const* sourceCode = "contract test {\n" From 6441a1d93d51b2f0ae896d16daf447389cc9f164 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 2 Feb 2015 15:03:44 +0100 Subject: [PATCH 3/4] Simple mapping accessors working --- libsolidity/ExpressionCompiler.cpp | 53 ++++++++---------------------- libsolidity/ExpressionCompiler.h | 4 +-- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index edd04256f..722ac9895 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -823,10 +823,10 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ return length; } -unsigned ExpressionCompiler::appendTypeCopyToMemory(Type const& _expectedType, TypePointer const& _type, - Location const& _location, unsigned _memoryOffset) +unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, + Location const& _location, unsigned _memoryOffset) { - appendTypeConversion(*_type, _expectedType, true); + appendTypeConversion(_type, _expectedType, true); unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); if (c_numBytes == 0 || c_numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() @@ -842,65 +842,40 @@ unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedT unsigned _memoryOffset) { _expression.accept(*this); - return appendTypeCopyToMemory(_expectedType, _expression.getType(), _expression.getLocation(), _memoryOffset); + return appendTypeConversionAndMoveToMemory(_expectedType, *_expression.getType(), _expression.getLocation(), _memoryOffset); } void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { - auto mappingType = dynamic_cast(_varDecl.getType().get()); + TypePointer resultType = _varDecl.getType(); + auto mappingType = dynamic_cast(resultType.get()); unsigned sizeOnStack; + if (mappingType != nullptr) { - // this copies from Compiler::visit(FunctionDefinition..) for argument reading - unsigned parameterSize = mappingType->getKeyType()->getSizeOnStack(); - m_context.adjustStackOffset(parameterSize); - m_context.addVariable(_varDecl, parameterSize); // this copies from ExpressionCompiler::visit(IndexAccess .. ) for mapping access TypePointer const& keyType = mappingType->getKeyType(); - unsigned length = appendTypeCopyToMemory(*keyType, mappingType->getValueType(), Location()); + unsigned length = appendTypeConversionAndMoveToMemory(*keyType, *keyType, Location()); solAssert(length == 32, "Mapping key has to take 32 bytes in memory (for now)."); // @todo move this once we actually use memory + m_context << m_context.getStorageLocationOfVariable(_varDecl); length += CompilerUtils(m_context).storeInMemory(length); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; - m_currentLValue = LValue(m_context, LValue::STORAGE, *mappingType->getValueType()); m_currentLValue.retrieveValue(mappingType->getValueType(), Location(), true); + m_currentLValue.reset(); - unsigned const c_argumentsSize = keyType->getSizeOnStack(); - unsigned const c_returnValuesSize = mappingType->getValueType()->getSizeOnStack(); - unsigned const c_localVariablesSize = 0; - - vector stackLayout; - stackLayout.push_back(c_returnValuesSize); // target of return address - stackLayout += vector(c_argumentsSize, -1); // discard all arguments - for (unsigned i = 0; i < c_returnValuesSize; ++i) - stackLayout.push_back(i); - stackLayout += vector(c_localVariablesSize, -1); - - while (stackLayout.back() != int(stackLayout.size() - 1)) - if (stackLayout.back() < 0) - { - m_context << eth::Instruction::POP; - stackLayout.pop_back(); - } - else - { - m_context << eth::swapInstruction(stackLayout.size() - stackLayout.back() - 1); - swap(stackLayout[stackLayout.back()], stackLayout.back()); - } - //@todo assert that everything is in place now - - m_context << eth::Instruction::JUMP; + resultType = mappingType->getValueType(); } else { m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType()); solAssert(m_currentLValue.isInStorage(), ""); m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true); - sizeOnStack = _varDecl.getType()->getSizeOnStack(); - solAssert(sizeOnStack <= 15, "Stack too deep."); - m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP; } + sizeOnStack = _varDecl.getType()->getSizeOnStack(); + solAssert(sizeOnStack <= 15, "Stack too deep."); + m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP; } diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index d93ab28ed..7de577e6c 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -99,8 +99,8 @@ private: unsigned _memoryOffset = 0); /// Appends code that copies a type to memory. /// @returns the number of bytes copied to memory - unsigned appendTypeCopyToMemory(Type const& _expectedType, TypePointer const& _type, - Location const& _location, unsigned _memoryOffset = 0); + unsigned appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, + Location const& _location, unsigned _memoryOffset = 0); /// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, From 6c5120978ececc5dc015721a0554c3a360e68827 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 2 Feb 2015 17:52:50 +0100 Subject: [PATCH 4/4] Accessors for multiple mappings implemented --- libsolidity/ExpressionCompiler.cpp | 45 +++++++++++++------------- libsolidity/Types.cpp | 22 ++++++------- test/SolidityEndToEndTest.cpp | 3 ++ test/SolidityNameAndTypeResolution.cpp | 15 +++++++-- 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 722ac9895..45e0e80b0 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -847,36 +848,34 @@ unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedT void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { - TypePointer resultType = _varDecl.getType(); - auto mappingType = dynamic_cast(resultType.get()); + FunctionType thisType(_varDecl); + solAssert(thisType.getReturnParameterTypes().size() == 1, ""); + TypePointer const& resultType = thisType.getReturnParameterTypes().front(); unsigned sizeOnStack; - if (mappingType != nullptr) - { - // this copies from ExpressionCompiler::visit(IndexAccess .. ) for mapping access - TypePointer const& keyType = mappingType->getKeyType(); - unsigned length = appendTypeConversionAndMoveToMemory(*keyType, *keyType, Location()); - solAssert(length == 32, "Mapping key has to take 32 bytes in memory (for now)."); - // @todo move this once we actually use memory - m_context << m_context.getStorageLocationOfVariable(_varDecl); - length += CompilerUtils(m_context).storeInMemory(length); - m_context << u256(length) << u256(0) << eth::Instruction::SHA3; - m_currentLValue = LValue(m_context, LValue::STORAGE, *mappingType->getValueType()); - m_currentLValue.retrieveValue(mappingType->getValueType(), Location(), true); - m_currentLValue.reset(); + unsigned length = 0; + TypePointers const& params = thisType.getParameterTypes(); + // move arguments to memory + for (TypePointer const& param: boost::adaptors::reverse(params)) + length += appendTypeConversionAndMoveToMemory(*param, *param, Location(), length); - resultType = mappingType->getValueType(); - } - else + // retrieve the position of the mapping + m_context << m_context.getStorageLocationOfVariable(_varDecl); + + for (TypePointer const& param: params) { - m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType()); - solAssert(m_currentLValue.isInStorage(), ""); - m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true); + // move offset to memory + CompilerUtils(m_context).storeInMemory(length); + unsigned argLen = CompilerUtils::getPaddedSize(param->getCalldataEncodedSize()); + length -= argLen; + m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3; } - sizeOnStack = _varDecl.getType()->getSizeOnStack(); + + m_currentLValue = LValue(m_context, LValue::STORAGE, *resultType); + m_currentLValue.retrieveValue(resultType, Location(), true); + sizeOnStack = resultType->getSizeOnStack(); solAssert(sizeOnStack <= 15, "Stack too deep."); m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP; - } ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7fa4561e3..cfb852c2f 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -626,20 +626,20 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): TypePointers retParams; vector retParamNames; TypePointer varDeclType = _varDecl.getType(); - auto mappingType = dynamic_cast(varDeclType.get()); - if (mappingType!= nullptr) - { - params.push_back(mappingType->getKeyType()); - paramNames.push_back(mappingType->getKeyType()->toString()); + auto mappingType = dynamic_cast(varDeclType.get()); + auto returnType = varDeclType; - retParams.push_back(mappingType->getValueType()); - retParamNames.push_back(mappingType->getValueType()->toString()); - } - else // elelemntary type + while (mappingType!= nullptr) { - retParams.push_back(varDeclType); - retParamNames.push_back(_varDecl.getName()); + params.push_back(mappingType->getKeyType()); + paramNames.push_back(""); + returnType = mappingType->getValueType(); + mappingType = dynamic_cast(mappingType->getValueType().get()); } + + retParams.push_back(returnType); + retParamNames.push_back(""); + swap(params, m_parameterTypes); swap(paramNames, m_parameterNames); swap(retParams, m_returnParameterTypes); diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 63a8ebcd3..9a04e02d3 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -925,16 +925,19 @@ BOOST_AUTO_TEST_CASE(complex_accessors) " mapping(uint256 => string4) to_string_map;\n" " mapping(uint256 => bool) to_bool_map;\n" " mapping(uint256 => uint256) to_uint_map;\n" + " mapping(uint256 => mapping(uint256 => uint256)) to_multiple_map;\n" " function test() {\n" " to_string_map[42] = \"24\";\n" " to_bool_map[42] = false;\n" " to_uint_map[42] = 12;\n" + " to_multiple_map[42][23] = 31;\n" " }\n" "}\n"; compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("to_string_map(uint256)", 42) == encodeArgs("24")); BOOST_CHECK(callContractFunction("to_bool_map(uint256)", 42) == encodeArgs(false)); BOOST_CHECK(callContractFunction("to_uint_map(uint256)", 42) == encodeArgs(12)); + BOOST_CHECK(callContractFunction("to_multiple_map(uint256,uint256)", 42, 23) == encodeArgs(31)); } BOOST_AUTO_TEST_CASE(balance) diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index df0e07e1d..2fe3288ad 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -638,6 +638,7 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors) " }\n" "uint256 foo;\n" "mapping(uint=>string4) map;\n" + "mapping(uint=>mapping(uint=>string4)) multiple_map;\n" "}\n"; ASTPointer source; @@ -649,10 +650,20 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors) auto returnParams = function->getReturnParameterTypeNames(); BOOST_CHECK_EQUAL(returnParams.at(0), "uint256"); BOOST_CHECK(function->isConstant()); + function = retrieveFunctionBySignature(contract, "map(uint256)"); BOOST_REQUIRE(function && function->hasDeclaration()); - auto Params = function->getParameterTypeNames(); - BOOST_CHECK_EQUAL(returnParams.at(0), "uint256"); + auto params = function->getParameterTypeNames(); + BOOST_CHECK_EQUAL(params.at(0), "uint256"); + returnParams = function->getReturnParameterTypeNames(); + BOOST_CHECK_EQUAL(returnParams.at(0), "string4"); + BOOST_CHECK(function->isConstant()); + + function = retrieveFunctionBySignature(contract, "multiple_map(uint256,uint256)"); + BOOST_REQUIRE(function && function->hasDeclaration()); + params = function->getParameterTypeNames(); + BOOST_CHECK_EQUAL(params.at(0), "uint256"); + BOOST_CHECK_EQUAL(params.at(1), "uint256"); returnParams = function->getReturnParameterTypeNames(); BOOST_CHECK_EQUAL(returnParams.at(0), "string4"); BOOST_CHECK(function->isConstant());