Correctly name builtin functions in error messages.

This commit is contained in:
Christian Parpart
2021-10-13 15:02:02 +02:00
parent 3fb42f60b4
commit 843171c70f
16 changed files with 229 additions and 118 deletions
+164 -76
View File
@@ -467,19 +467,23 @@ bool AddressType::operator==(Type const& _other) const
MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const
{
auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member {
return {FunctionType::magicName(_functionType->kind()), _functionType};
};
MemberList::MemberMap members = {
{"balance", TypeProvider::uint256()},
{"code", TypeProvider::array(DataLocation::Memory)},
{"codehash", TypeProvider::fixedBytes(32)},
{"call", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)},
{"callcode", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)},
{"delegatecall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false, StateMutability::NonPayable)},
{"staticcall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)}
{"balance"sv, TypeProvider::uint256()},
{"code"sv, TypeProvider::array(DataLocation::Memory)},
{"codehash"sv, TypeProvider::fixedBytes(32)},
magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)),
magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)),
magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false, StateMutability::NonPayable)),
magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View))
};
if (m_stateMutability == StateMutability::Payable)
{
members.emplace_back(MemberList::Member{"send", TypeProvider::function(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send, false, StateMutability::NonPayable)});
members.emplace_back(MemberList::Member{"transfer", TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, false, StateMutability::NonPayable)});
members.emplace_back(magicFunc(TypeProvider::function(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send, false, StateMutability::NonPayable)));
members.emplace_back(magicFunc(TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, false, StateMutability::NonPayable)));
}
return members;
}
@@ -1806,28 +1810,32 @@ MemberList::MemberMap ArrayType::nativeMembers(ASTNode const*) const
members.emplace_back("length", TypeProvider::uint256());
if (isDynamicallySized() && location() == DataLocation::Storage)
{
auto const magicBoundFunc = [](FunctionType const* _functionType) -> MemberList::Member {
return {FunctionType::magicName(_functionType->kind()), _functionType->asBoundFunction()};
};
Type const* thisAsPointer = TypeProvider::withLocation(this, location(), true);
members.emplace_back("push", TypeProvider::function(
members.emplace_back(magicBoundFunc(TypeProvider::function(
TypePointers{thisAsPointer},
TypePointers{baseType()},
strings{string()},
strings{string()},
FunctionType::Kind::ArrayPush
)->asBoundFunction());
members.emplace_back("push", TypeProvider::function(
)));
members.emplace_back(magicBoundFunc(TypeProvider::function(
TypePointers{thisAsPointer, baseType()},
TypePointers{},
strings{string(),string()},
strings{},
FunctionType::Kind::ArrayPush
)->asBoundFunction());
members.emplace_back("pop", TypeProvider::function(
)));
members.emplace_back(magicBoundFunc(TypeProvider::function(
TypePointers{thisAsPointer},
TypePointers{},
strings{string()},
strings{},
FunctionType::Kind::ArrayPop
)->asBoundFunction());
)));
}
}
return members;
@@ -3030,22 +3038,96 @@ string FunctionType::canonicalName() const
return "function";
}
string_view FunctionType::magicName(Kind _kind) // TODO(pr): maybe call it languageIdentifier(.) instead
{
switch (_kind)
{
// magic funcs and vars
case Kind::AddMod: return "addmod"sv;
case Kind::Assert: return "assert"sv;
case Kind::BlockHash: return "blockhash"sv;
case Kind::ECRecover: return "ecrecover"sv;
case Kind::Require: return "require"sv;
case Kind::GasLeft: return "gasleft"sv;
case Kind::KECCAK256: return "keccak256"sv; // NB: sha3 is an alias to keccak256
case Kind::MulMod: return "mulmod"sv;
case Kind::Revert: return "revert"sv;
case Kind::RIPEMD160: return "ripemd160"sv;
case Kind::Selfdestruct: return "selfdestruct"sv; // NB: suicide() is an alias to selfdestruct()
case Kind::SHA256: return "sha256"sv;
case Kind::MetaType: return "type"sv;
// native members: ArrayType
case Kind::ArrayPop: return "pop"sv;
case Kind::ArrayPush: return "push"sv;
// native members: AddressType
case Kind::BareCall: return "call"sv;
case Kind::BareCallCode: return "callcode"sv;
case Kind::BareDelegateCall: return "delegatecall"sv;
case Kind::BareStaticCall: return "staticcall"sv;
case Kind::Send: return "send"sv;
case Kind::Transfer: return "transfer"sv;
// FunctionType
case Kind::SetValue: return "value"sv;
case Kind::SetGas: return "gas"sv;
// TypeType
case Kind::Unwrap: return "unwrap"sv;
case Kind::Wrap: return "wrap"sv;
case Kind::BytesConcat: return "concat"sv;
// MagicType
case Kind::ABIEncode: return "encode"sv;
case Kind::ABIDecode: return "decode"sv;
case Kind::ABIEncodePacked: return "encodePacked"sv;
case Kind::ABIEncodeWithSelector: return "encodeWithSelector"sv;
case Kind::ABIEncodeWithSignature: return "encodeWithSignature"sv;
// user defined
case Kind::Error:
case Kind::Event:
case Kind::Creation:
case Kind::Declaration:
case Kind::DelegateCall:
case Kind::External:
case Kind::Internal:
case Kind::ObjectCreation:
break;
}
return ""sv;
}
string FunctionType::toString(bool _short) const
{
string name = "function ";
if (m_kind == Kind::Declaration)
string name;
if (m_kind == Kind::Event)
name += "event " + m_declaration->name();
else if (m_kind == Kind::Error)
name += "error " + m_declaration->name();
else if (magicName(m_kind) != "")
name += magicName(m_kind);
else if (m_kind == Kind::Declaration)
{
name += "function ";
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(m_declaration);
solAssert(functionDefinition, "");
if (auto const* contract = dynamic_cast<ContractDefinition const*>(functionDefinition->scope()))
name += *contract->annotation().canonicalName + ".";
name += functionDefinition->name();
}
else
name += "function ";
name += '(';
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
name += ")";
if (m_stateMutability != StateMutability::NonPayable)
if (m_stateMutability != StateMutability::NonPayable && m_kind != Kind::Error)
name += " " + stateMutabilityToString(m_stateMutability);
if (m_kind == Kind::External)
name += " external";
@@ -3190,6 +3272,11 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
{
auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member {
return {FunctionType::magicName(_functionType->kind()), _functionType};
};
switch (m_kind)
{
case Kind::Declaration:
@@ -3229,40 +3316,34 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
if (m_kind != Kind::BareDelegateCall)
{
if (isPayable())
members.emplace_back(
"value",
TypeProvider::function(
parseElementaryTypeVector({"uint"}),
TypePointers{copyAndSetCallOptions(false, true, false)},
strings(1, ""),
strings(1, ""),
Kind::SetValue,
false,
StateMutability::Pure,
nullptr,
m_gasSet,
m_valueSet,
m_saltSet
)
);
}
if (m_kind != Kind::Creation)
members.emplace_back(
"gas",
TypeProvider::function(
members.emplace_back(magicFunc(TypeProvider::function(
parseElementaryTypeVector({"uint"}),
TypePointers{copyAndSetCallOptions(true, false, false)},
TypePointers{copyAndSetCallOptions(false, true, false)},
strings(1, ""),
strings(1, ""),
Kind::SetGas,
Kind::SetValue,
false,
StateMutability::Pure,
nullptr,
m_gasSet,
m_valueSet,
m_saltSet
)
);
)));
}
if (m_kind != Kind::Creation)
members.emplace_back(magicFunc(TypeProvider::function(
parseElementaryTypeVector({"uint"}),
TypePointers{copyAndSetCallOptions(true, false, false)},
strings(1, ""),
strings(1, ""),
Kind::SetGas,
false,
StateMutability::Pure,
nullptr,
m_gasSet,
m_valueSet,
m_saltSet
)));
return members;
}
case Kind::DelegateCall:
@@ -3720,6 +3801,11 @@ vector<tuple<string, Type const*>> TypeType::makeStackItems() const
MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) const
{
auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member {
return {FunctionType::magicName(_functionType->kind()), _functionType};
};
MemberList::MemberMap members;
if (m_actualType->category() == Category::Contract)
{
@@ -3794,8 +3880,7 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
else if (m_actualType->category() == Category::UserDefinedValueType)
{
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(*m_actualType);
members.emplace_back(
"wrap",
members.emplace_back(magicFunc(
TypeProvider::function(
TypePointers{&userDefined.underlyingType()},
TypePointers{&userDefined},
@@ -3805,9 +3890,8 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
false, /*_arbitraryParameters */
StateMutability::Pure
)
);
members.emplace_back(
"unwrap",
));
members.emplace_back(magicFunc(
TypeProvider::function(
TypePointers{&userDefined},
TypePointers{&userDefined.underlyingType()},
@@ -3817,13 +3901,13 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
false, /* _arbitraryParameters */
StateMutability::Pure
)
);
));
}
else if (
auto const* arrayType = dynamic_cast<ArrayType const*>(m_actualType);
arrayType && arrayType->isByteArray()
)
members.emplace_back("concat", TypeProvider::function(
members.emplace_back(magicFunc(TypeProvider::function(
TypePointers{},
TypePointers{TypeProvider::bytesMemory()},
strings{},
@@ -3831,7 +3915,7 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
FunctionType::Kind::BytesConcat,
/* _arbitraryParameters */ true,
StateMutability::Pure
));
)));
return members;
}
@@ -3947,35 +4031,39 @@ bool MagicType::operator==(Type const& _other) const
MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
{
auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member {
return {FunctionType::magicName(_functionType->kind()), _functionType};
};
switch (m_kind)
{
case Kind::Block:
return MemberList::MemberMap({
{"coinbase", TypeProvider::payableAddress()},
{"timestamp", TypeProvider::uint256()},
{"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)},
{"difficulty", TypeProvider::uint256()},
{"number", TypeProvider::uint256()},
{"gaslimit", TypeProvider::uint256()},
{"chainid", TypeProvider::uint256()},
{"basefee", TypeProvider::uint256()}
{"coinbase"sv, TypeProvider::payableAddress()},
{"timestamp"sv, TypeProvider::uint256()},
magicFunc(TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
{"difficulty"sv, TypeProvider::uint256()},
{"number"sv, TypeProvider::uint256()},
{"gaslimit"sv, TypeProvider::uint256()},
{"chainid"sv, TypeProvider::uint256()},
{"basefee"sv, TypeProvider::uint256()}
});
case Kind::Message:
return MemberList::MemberMap({
{"sender", TypeProvider::address()},
{"gas", TypeProvider::uint256()},
{"value", TypeProvider::uint256()},
{"data", TypeProvider::array(DataLocation::CallData)},
{"sig", TypeProvider::fixedBytes(4)}
{"sender"sv, TypeProvider::address()},
{"gas"sv, TypeProvider::uint256()},
{"value"sv, TypeProvider::uint256()},
{"data"sv, TypeProvider::array(DataLocation::CallData)},
{"sig"sv, TypeProvider::fixedBytes(4)}
});
case Kind::Transaction:
return MemberList::MemberMap({
{"origin", TypeProvider::address()},
{"gasprice", TypeProvider::uint256()}
{"origin"sv, TypeProvider::address()},
{"gasprice"sv, TypeProvider::uint256()}
});
case Kind::ABI:
return MemberList::MemberMap({
{"encode", TypeProvider::function(
magicFunc(TypeProvider::function(
TypePointers{},
TypePointers{TypeProvider::array(DataLocation::Memory)},
strings{},
@@ -3983,8 +4071,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIEncode,
true,
StateMutability::Pure
)},
{"encodePacked", TypeProvider::function(
)),
magicFunc(TypeProvider::function(
TypePointers{},
TypePointers{TypeProvider::array(DataLocation::Memory)},
strings{},
@@ -3992,8 +4080,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIEncodePacked,
true,
StateMutability::Pure
)},
{"encodeWithSelector", TypeProvider::function(
)),
magicFunc(TypeProvider::function(
TypePointers{TypeProvider::fixedBytes(4)},
TypePointers{TypeProvider::array(DataLocation::Memory)},
strings{1, ""},
@@ -4001,8 +4089,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIEncodeWithSelector,
true,
StateMutability::Pure
)},
{"encodeWithSignature", TypeProvider::function(
)),
magicFunc(TypeProvider::function(
TypePointers{TypeProvider::array(DataLocation::Memory, true)},
TypePointers{TypeProvider::array(DataLocation::Memory)},
strings{1, ""},
@@ -4010,8 +4098,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIEncodeWithSignature,
true,
StateMutability::Pure
)},
{"decode", TypeProvider::function(
)),
magicFunc(TypeProvider::function(
TypePointers(),
TypePointers(),
strings{},
@@ -4019,7 +4107,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIDecode,
true,
StateMutability::Pure
)}
))
});
case Kind::MetaType:
{
+6 -1
View File
@@ -101,7 +101,7 @@ public:
struct Member
{
/// Manual constructor for members that are not taken from a declaration.
Member(char const* _name, Type const* _type):
Member(std::string_view _name, Type const* _type):
name(_name),
type(_type),
declaration(nullptr)
@@ -1245,6 +1245,11 @@ public:
Declaration,
};
/// Returns the magic name of this function kind, if there is any.
///
/// If there is no magic or native name for this function, an empty string is returned instead.
static std::string_view magicName(Kind _kind);
/// Creates the type of a function.
/// @arg _kind must be Kind::Internal, Kind::External or Kind::Declaration.
explicit FunctionType(FunctionDefinition const& _function, Kind _kind = Kind::Declaration);