mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Fixed function overloads.
Added tests, disallowed non-calling usage of non-unique function references.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#include <libdevcore/CommonIO.h>
|
||||
#include <libdevcore/CommonData.h>
|
||||
#include <libdevcrypto/SHA3.h>
|
||||
#include <libsolidity/Utils.h>
|
||||
#include <libsolidity/AST.h>
|
||||
|
||||
@@ -92,13 +93,13 @@ std::pair<u256, unsigned> const* MemberList::getMemberStorageOffset(string const
|
||||
{
|
||||
TypePointers memberTypes;
|
||||
memberTypes.reserve(m_memberTypes.size());
|
||||
for (auto const& nameAndType: m_memberTypes)
|
||||
memberTypes.push_back(nameAndType.second);
|
||||
for (auto const& member: m_memberTypes)
|
||||
memberTypes.push_back(member.type);
|
||||
m_storageOffsets.reset(new StorageOffsets());
|
||||
m_storageOffsets->computeOffsets(memberTypes);
|
||||
}
|
||||
for (size_t index = 0; index < m_memberTypes.size(); ++index)
|
||||
if (m_memberTypes[index].first == _name)
|
||||
if (m_memberTypes[index].name == _name)
|
||||
return m_storageOffsets->getOffset(index);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -189,7 +190,7 @@ TypePointer Type::fromArrayTypeName(TypeName& _baseTypeName, Expression* _length
|
||||
if (_length)
|
||||
{
|
||||
if (!_length->getType())
|
||||
_length->checkTypeRequirements();
|
||||
_length->checkTypeRequirements(nullptr);
|
||||
auto const* length = dynamic_cast<IntegerConstantType const*>(_length->getType().get());
|
||||
if (!length)
|
||||
BOOST_THROW_EXCEPTION(_length->createTypeError("Invalid array length."));
|
||||
@@ -793,18 +794,46 @@ MemberList const& ContractType::getMembers() const
|
||||
if (!m_members)
|
||||
{
|
||||
// All address members and all interface functions
|
||||
vector<pair<string, TypePointer>> members(IntegerType::AddressMemberList.begin(),
|
||||
IntegerType::AddressMemberList.end());
|
||||
MemberList::MemberMap members(
|
||||
IntegerType::AddressMemberList.begin(),
|
||||
IntegerType::AddressMemberList.end()
|
||||
);
|
||||
if (m_super)
|
||||
{
|
||||
// add the most derived of all functions which are visible in derived contracts
|
||||
for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts())
|
||||
for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions())
|
||||
if (function->isVisibleInDerivedContracts())
|
||||
members.push_back(make_pair(function->getName(), make_shared<FunctionType>(*function, true)));
|
||||
{
|
||||
if (!function->isVisibleInDerivedContracts())
|
||||
continue;
|
||||
auto functionType = make_shared<FunctionType>(*function, true);
|
||||
bool functionWithEqualArgumentsFound = false;
|
||||
for (auto const& member: members)
|
||||
{
|
||||
if (member.name != function->getName())
|
||||
continue;
|
||||
auto memberType = dynamic_cast<FunctionType const*>(member.type.get());
|
||||
solAssert(!!memberType, "Override changes type.");
|
||||
if (!memberType->hasEqualArgumentTypes(*functionType))
|
||||
continue;
|
||||
functionWithEqualArgumentsFound = true;
|
||||
break;
|
||||
}
|
||||
if (!functionWithEqualArgumentsFound)
|
||||
members.push_back(MemberList::Member(
|
||||
function->getName(),
|
||||
functionType,
|
||||
function.get()
|
||||
));
|
||||
}
|
||||
}
|
||||
else
|
||||
for (auto const& it: m_contract.getInterfaceFunctions())
|
||||
members.push_back(make_pair(it.second->getDeclaration().getName(), it.second));
|
||||
members.push_back(MemberList::Member(
|
||||
it.second->getDeclaration().getName(),
|
||||
it.second,
|
||||
&it.second->getDeclaration()
|
||||
));
|
||||
m_members.reset(new MemberList(members));
|
||||
}
|
||||
return *m_members;
|
||||
@@ -823,16 +852,6 @@ shared_ptr<FunctionType const> const& ContractType::getConstructorType() const
|
||||
return m_constructorType;
|
||||
}
|
||||
|
||||
u256 ContractType::getFunctionIdentifier(string const& _functionName) const
|
||||
{
|
||||
auto interfaceFunctions = m_contract.getInterfaceFunctions();
|
||||
for (auto const& it: m_contract.getInterfaceFunctions())
|
||||
if (it.second->getDeclaration().getName() == _functionName)
|
||||
return FixedHash<4>::Arith(it.first);
|
||||
|
||||
return Invalid256;
|
||||
}
|
||||
|
||||
vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::getStateVariables() const
|
||||
{
|
||||
vector<VariableDeclaration const*> variables;
|
||||
@@ -873,8 +892,8 @@ u256 StructType::getStorageSize() const
|
||||
|
||||
bool StructType::canLiveOutsideStorage() const
|
||||
{
|
||||
for (pair<string, TypePointer> const& member: getMembers())
|
||||
if (!member.second->canLiveOutsideStorage())
|
||||
for (auto const& member: getMembers())
|
||||
if (!member.type->canLiveOutsideStorage())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -891,7 +910,7 @@ MemberList const& StructType::getMembers() const
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
|
||||
members.push_back(make_pair(variable->getName(), variable->getType()));
|
||||
members.push_back(MemberList::Member(variable->getName(), variable->getType(), variable.get()));
|
||||
m_members.reset(new MemberList(members));
|
||||
}
|
||||
return *m_members;
|
||||
@@ -996,11 +1015,11 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
||||
vector<string> retParamNames;
|
||||
if (auto structType = dynamic_cast<StructType const*>(returnType.get()))
|
||||
{
|
||||
for (pair<string, TypePointer> const& member: structType->getMembers())
|
||||
if (member.second->canLiveOutsideStorage())
|
||||
for (auto const& member: structType->getMembers())
|
||||
if (member.type->canLiveOutsideStorage())
|
||||
{
|
||||
retParamNames.push_back(member.first);
|
||||
retParams.push_back(member.second);
|
||||
retParamNames.push_back(member.name);
|
||||
retParams.push_back(member.type);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1130,12 +1149,12 @@ MemberList const& FunctionType::getMembers() const
|
||||
case Location::Bare:
|
||||
if (!m_members)
|
||||
{
|
||||
vector<pair<string, TypePointer>> members{
|
||||
MemberList::MemberMap members{
|
||||
{"value", make_shared<FunctionType>(parseElementaryTypeVector({"uint"}),
|
||||
TypePointers{copyAndSetGasOrValue(false, true)},
|
||||
Location::SetValue, false, m_gasSet, m_valueSet)}};
|
||||
if (m_location != Location::Creation)
|
||||
members.push_back(make_pair("gas", make_shared<FunctionType>(
|
||||
members.push_back(MemberList::Member("gas", make_shared<FunctionType>(
|
||||
parseElementaryTypeVector({"uint"}),
|
||||
TypePointers{copyAndSetGasOrValue(true, false)},
|
||||
Location::SetGas, false, m_gasSet, m_valueSet)));
|
||||
@@ -1147,6 +1166,37 @@ MemberList const& FunctionType::getMembers() const
|
||||
}
|
||||
}
|
||||
|
||||
bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes) const
|
||||
{
|
||||
TypePointers const& parameterTypes = getParameterTypes();
|
||||
if (takesArbitraryParameters())
|
||||
return true;
|
||||
else if (_argumentTypes.size() != parameterTypes.size())
|
||||
return false;
|
||||
else
|
||||
return std::equal(
|
||||
_argumentTypes.cbegin(),
|
||||
_argumentTypes.cend(),
|
||||
parameterTypes.cbegin(),
|
||||
[](TypePointer const& argumentType, TypePointer const& parameterType)
|
||||
{
|
||||
return argumentType->isImplicitlyConvertibleTo(*parameterType);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
bool FunctionType::hasEqualArgumentTypes(FunctionType const& _other) const
|
||||
{
|
||||
if (m_parameterTypes.size() != _other.m_parameterTypes.size())
|
||||
return false;
|
||||
return equal(
|
||||
m_parameterTypes.cbegin(),
|
||||
m_parameterTypes.cend(),
|
||||
_other.m_parameterTypes.cbegin(),
|
||||
[](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; }
|
||||
);
|
||||
}
|
||||
|
||||
string FunctionType::externalSignature(std::string const& _name) const
|
||||
{
|
||||
std::string funcName = _name;
|
||||
@@ -1167,6 +1217,11 @@ string FunctionType::externalSignature(std::string const& _name) const
|
||||
return ret + ")";
|
||||
}
|
||||
|
||||
u256 FunctionType::externalIdentifier() const
|
||||
{
|
||||
return FixedHash<4>::Arith(FixedHash<4>(dev::sha3(externalSignature())));
|
||||
}
|
||||
|
||||
TypePointers FunctionType::parseElementaryTypeVector(strings const& _types)
|
||||
{
|
||||
TypePointers pointers;
|
||||
@@ -1250,7 +1305,7 @@ MemberList const& TypeType::getMembers() const
|
||||
// We need to lazy-initialize it because of recursive references.
|
||||
if (!m_members)
|
||||
{
|
||||
vector<pair<string, TypePointer>> members;
|
||||
MemberList::MemberMap members;
|
||||
if (m_actualType->getCategory() == Category::Contract && m_currentContract != nullptr)
|
||||
{
|
||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).getContractDefinition();
|
||||
@@ -1259,14 +1314,14 @@ MemberList const& TypeType::getMembers() const
|
||||
// We are accessing the type of a base contract, so add all public and protected
|
||||
// members. Note that this does not add inherited functions on purpose.
|
||||
for (Declaration const* decl: contract.getInheritableMembers())
|
||||
members.push_back(make_pair(decl->getName(), decl->getType()));
|
||||
members.push_back(MemberList::Member(decl->getName(), decl->getType(), decl));
|
||||
}
|
||||
else if (m_actualType->getCategory() == Category::Enum)
|
||||
{
|
||||
EnumDefinition const& enumDef = dynamic_cast<EnumType const&>(*m_actualType).getEnumDefinition();
|
||||
auto enumType = make_shared<EnumType>(enumDef);
|
||||
for (ASTPointer<EnumValue> const& enumValue: enumDef.getMembers())
|
||||
members.push_back(make_pair(enumValue->getName(), enumType));
|
||||
members.push_back(MemberList::Member(enumValue->getName(), enumType));
|
||||
}
|
||||
m_members.reset(new MemberList(members));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user