Clean up interface inheritance code

This commit is contained in:
Bhargava Shastry 2020-04-11 19:35:20 +02:00
parent 91786d02b6
commit 3ef6e09258
2 changed files with 194 additions and 66 deletions

View File

@ -141,13 +141,11 @@ string libraryFunctionMutability(SolLibraryFunctionStateMutability _mut)
SolInterfaceFunction::SolInterfaceFunction(
std::string _functionName,
SolFunctionStateMutability _mutability,
bool _override
SolFunctionStateMutability _mutability
)
{
m_functionName = _functionName;
m_mutability = _mutability;
m_override = _override;
}
bool SolInterfaceFunction::operator==(SolInterfaceFunction const& _rhs) const
@ -164,23 +162,10 @@ bool SolInterfaceFunction::operator!=(SolInterfaceFunction const& _rhs) const
string SolInterfaceFunction::str() const
{
string bodyStr = Whiskers(R"(
{
return <uint>;
})")
("uint", "0")
.render();
return Whiskers(R"(
function <functionName>() external <stateMutability><?isOverride> override</isOverride>
<?isVirtual> virtual</isVirtual> returns (uint)<?isImplemented><body><!isImplemented>;</isImplemented>
)")
function <functionName>() external <stateMutability> returns (uint);)")
("functionName", name())
("stateMutability", functionMutability(mutability()))
("isOverride", override())
("isVirtual", isVirtual())
("isImplemented", implement())
("body", bodyStr)
.render();
}
@ -295,7 +280,7 @@ void SolInterface::overrideHelper(
{
// Report error if state mutability of identically
// named functions differ
if (m.first->mutability() != _function->mutability())
if (m.first->mutability() != mutability)
assertThrow(
false,
langutil::FuzzerError,
@ -303,23 +288,47 @@ void SolInterface::overrideHelper(
" and parameter types but different mutability."
);
// Add new base to list of overridden bases
m_overrideMap[m.first].push_back(_base);
m_overrideMap[m.first].push_back(
shared_ptr<IFunctionOverride>(
make_shared<IFunctionOverride>(
IFunctionOverride(
_base,
_function,
this,
false,
false,
true,
""
)
)
)
);
multipleOverride = true;
break;
}
}
// If function has not been overridden, add new override
// Use a pseudo-random coin flip to decide whether to override explicitly
// or not. Implicit override means that the overridden function is not
// redeclared with the override keyword.
bool explicitOverride = coinFlip();
// If function has not been overridden, add new override pseudo-randomly
if (!multipleOverride)
m_overrideMap.insert(
pair(
make_shared<SolInterfaceFunction>(
SolInterfaceFunction(
functionName,
mutability,
true
_function,
vector<shared_ptr<IFunctionOverride>>{
make_shared<IFunctionOverride>(
IFunctionOverride(
_base,
_function,
this,
false,
false,
explicitOverride,
""
)
)
),
vector<shared_ptr<SolInterface>>{_base}
}
)
);
}
@ -343,7 +352,9 @@ void SolInterface::addBases(Interface const& _interface)
{
auto base = make_shared<SolInterface>(SolInterface(b, newBaseName(), m_prng));
m_baseInterfaces.push_back(base);
#if 0
cout << "Added " << base->name() << " as base" << endl;
#endif
// Worst case, we override all base functions so we
// increment derived contract's function index by
// this amount.
@ -367,7 +378,9 @@ void SolInterface::addFunctions(Interface const& _interface)
SolInterface::SolInterface(Interface const& _interface, string _name, shared_ptr<SolRandomNumGenerator> _prng)
{
#if 0
cout << "Constructing " << _name << endl;
#endif
m_prng = _prng;
m_interfaceName = _name;
m_lastBaseName = m_interfaceName;
@ -411,12 +424,14 @@ string SolInterface::overrideStr() const
{
overriddenBaseNames << Whiskers(R"(<sep><name>)")
("sep", sep)
("name", b->name())
("name", b->baseName())
.render();
if (sep.empty())
sep = ", ";
}
}
else if (coinFlip())
continue;
overriddenFunctions << Whiskers(R"(
function <functionName>() external <stateMutability> override<?multiple>(<baseNames>)</multiple> returns (uint);)")
("functionName", f.first->name())
@ -659,4 +674,101 @@ string CFunctionOverride::str() const
// return get<shared_ptr<SolContract const>>(base)->name();
// solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
// return get<shared_ptr<SolInterface const>>(base)->name();
//}
//}
IFunctionOverride::IFunctionOverride(
std::shared_ptr<SolInterface const> _baseInterface,
std::shared_ptr<SolInterfaceFunction const> _baseFunction,
std::variant<SolInterface*, SolContract*> _derivedProgram,
bool _implement,
bool _virtual,
bool _explicitInherit,
std::string _returnValue
)
{
if (std::holds_alternative<SolContract*>(_derivedProgram))
{
auto derived = std::get<SolContract*>(_derivedProgram);
m_derivedType = derived->abstract() ? DerivedType::ABSTRACTCONTRACT : DerivedType::CONTRACT;
if (!derived->abstract())
assertThrow(
_explicitInherit && !_returnValue.empty() && _implement,
langutil::FuzzerError,
"Contract overrides base interface function either without"
" implementing it or implictly overrides."
);
else
if (_explicitInherit)
assertThrow(
_virtual || (_implement && !_returnValue.empty()),
langutil::FuzzerError,
"Abstract contract overrides base interface function either"
" without implementing it or without marking it virtual."
);
}
else
{
assertThrow(holds_alternative<SolInterface*>(_derivedProgram),
langutil::FuzzerError,
"Derived program neither an interface nor a contract"
);
m_derivedType = DerivedType::INTERFACE;
if (_explicitInherit)
assertThrow(
!_virtual && !_implement && !_returnValue.empty(),
langutil::FuzzerError,
"Interface overrides base interface function with invalid parameters."
);
}
m_baseInterface = _baseInterface;
m_baseFunction = _baseFunction;
m_derivedProgram = _derivedProgram;
m_implemented = _implement;
m_virtualized = _virtual;
m_explicitlyInherited = _explicitInherit;
m_returnValue = _returnValue;
}
std::string IFunctionOverride::str() const
{
switch (m_derivedType)
{
case DerivedType::INTERFACE:
return interfaceStr();
case DerivedType::ABSTRACTCONTRACT:
case DerivedType::CONTRACT:
return contractStr();
}
}
string IFunctionOverride::interfaceStr() const
{
return Whiskers(R"(
function <functionName>() external <mutability> override returns(uint);
)")
("functionName", m_baseFunction->name())
("mutability", functionMutability(m_baseFunction->mutability()))
.render();
}
string IFunctionOverride::contractStr() const
{
string bodyStr = Whiskers(R"(
{
return <uint>;
})")
("uint", returnValue())
.render();
return Whiskers(R"(
function <functionName>() external <mutability> override
<?isVirtual> virtual</isVirtual> returns(uint)<?isImplemented><body><!isImplemented>;</isImplemented>
)")
("functionName", m_baseFunction->name())
("mutability", functionMutability(m_baseFunction->mutability()))
("isVirtual", virtualized())
("isImplemented", implemented())
("body", bodyStr)
.render();
}

View File

@ -90,8 +90,7 @@ struct SolInterfaceFunction
{
SolInterfaceFunction(
std::string _functionName,
SolFunctionStateMutability _mutability,
bool _override = false
SolFunctionStateMutability _mutability
);
bool operator==(SolInterfaceFunction const& _rhs) const;
bool operator!=(SolInterfaceFunction const& _rhs) const;
@ -105,24 +104,9 @@ struct SolInterfaceFunction
{
return m_mutability;
}
bool override() const
{
return m_override;
}
bool isVirtual() const
{
return false;
}
bool implement() const
{
return false;
}
std::string m_functionName;
SolFunctionStateMutability m_mutability = SolFunctionStateMutability::PURE;
bool m_override = false;
bool m_virtual = false;
bool m_implement = false;
};
struct SolContractFunction
@ -387,7 +371,7 @@ struct SolInterface
std::string m_interfaceName;
std::vector<std::shared_ptr<SolInterfaceFunction>> m_interfaceFunctions;
std::vector<std::shared_ptr<SolInterface>> m_baseInterfaces;
InterfaceOverrideMap m_overrideMap;
std::map<std::shared_ptr<SolInterfaceFunction>, std::vector<std::shared_ptr<IFunctionOverride>>> m_overrideMap;
std::shared_ptr<SolRandomNumGenerator> m_prng;
};
@ -466,25 +450,48 @@ struct CFunctionOverride
}
};
/* Difference between interface function declaration and interface
* function override is that the former can not be implemented and
* should not be marked virtual i.e., virtual is implicit.
*
* Interface function declarations may be implicitly or explicitly
* inherited by derived interfaces. To explicitly inherit base
* interface's function declaration, derived base must redeclare
* the said function and mark it override. If base interface function
* does not redeclare base interface function, it implicitly inherits
* it from base and exposes it to its derived interfaces.
*
* Interface functions inherited by contracts may be implicitly or
* explicitly inherited. Derived non abstract contracts must explicitly
* override and implement inherited interface functions unless they have
* already been implemented by one of its bases. Abstract contracts
* may implicitly or explicitly inherit base interface functions. If
* explicitly inherited, they must be redeclared and marked override.
* When a base interface function is explicitly inherited by a contract
* it may be marked virtual.
*/
struct IFunctionOverride
{
IFunctionOverride(
std::vector<std::shared_ptr<SolInterface const>> _base,
std::unique_ptr<SolInterfaceFunction const> _function,
bool _implement,
bool _virtual,
bool _redeclare,
std::string _returnValue = ""
)
{
m_function = std::make_pair(_base, std::move(_function));
m_implemented = _implement;
m_virtualized = _virtual;
m_redeclared = _redeclare;
m_returnValue = _returnValue;
}
enum class DerivedType
{
INTERFACE,
ABSTRACTCONTRACT,
CONTRACT
};
IFunctionOverride(
std::shared_ptr<SolInterface const> _baseInterface,
std::shared_ptr<SolInterfaceFunction const> _baseFunction,
std::variant<SolInterface*, SolContract*> _derivedProgram,
bool _implement,
bool _virtual,
bool _explicitInherit,
std::string _returnValue
);
std::string str() const;
std::string interfaceStr() const;
std::string contractStr() const;
bool implemented() const
{
@ -496,9 +503,9 @@ IFunctionOverride(
return m_virtualized;
}
bool redeclared() const
bool explicitlyInherited() const
{
return m_redeclared;
return m_explicitlyInherited;
}
std::string returnValue() const
@ -506,15 +513,24 @@ IFunctionOverride(
return m_returnValue;
}
OverrideIFunction m_function;
std::string baseName() const
{
return m_baseInterface->name();
}
std::shared_ptr<SolInterface const> m_baseInterface;
std::shared_ptr<SolInterfaceFunction const> m_baseFunction;
std::variant<SolInterface*, SolContract*> m_derivedProgram;
/// Flag that is true if overridden function is implemented in derived contract
bool m_implemented = false;
/// Flag that is true if overridden function implemented in derived contract is
/// marked virtual
bool m_virtualized = false;
/// Flag that is true if overridden function is redeclared but not implemented
bool m_redeclared = false;
bool m_explicitlyInherited = false;
/// The uint value to be returned if the overridden interface function is implemented
std::string m_returnValue;
DerivedType m_derivedType;
};
}