[SMTChecker] Fix super and virtual

This commit is contained in:
Leonardo Alt
2021-01-28 18:51:29 +01:00
parent d753c1a047
commit 545305a31f
18 changed files with 430 additions and 59 deletions
+50 -23
View File
@@ -30,6 +30,8 @@
#include <libsmtutil/SMTPortfolio.h>
#include <libsmtutil/Helpers.h>
#include <range/v3/view.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/adaptor/reversed.hpp>
@@ -112,7 +114,7 @@ bool SMTEncoder::visit(ContractDefinition const& _contract)
// the constructor.
// Constructors are visited as part of the constructor
// hierarchy inlining.
for (auto const* function: contractFunctions(_contract))
for (auto const* function: contractFunctionsWithoutVirtual(_contract))
if (!function->isConstructor())
function->accept(*this);
@@ -776,6 +778,7 @@ void SMTEncoder::initFunction(FunctionDefinition const& _function)
createLocalVariables(_function);
m_arrayAssignmentHappened = false;
clearIndices(m_currentContract, &_function);
m_variableUsage.setCurrentFunction(_function);
m_checked = true;
}
@@ -2534,6 +2537,14 @@ bool SMTEncoder::visitedFunction(FunctionDefinition const* _funDef)
return false;
}
ContractDefinition const* SMTEncoder::currentScopeContract()
{
for (auto&& f: m_callStack | ranges::views::reverse | ranges::views::keys)
if (auto fun = dynamic_cast<FunctionDefinition const*>(f))
return fun->annotation().contract;
return nullptr;
}
SMTEncoder::VariableIndices SMTEncoder::copyVariableIndices()
{
VariableIndices indices;
@@ -2678,7 +2689,11 @@ string SMTEncoder::extraComment()
return extra;
}
pair<FunctionDefinition const*, ContractDefinition const*> SMTEncoder::functionCallToDefinition(FunctionCall const& _funCall, ContractDefinition const* _contract)
FunctionDefinition const* SMTEncoder::functionCallToDefinition(
FunctionCall const& _funCall,
ContractDefinition const* _scopeContract,
ContractDefinition const* _contextContract
)
{
if (*_funCall.annotation().kind != FunctionCallKind::FunctionCall)
return {};
@@ -2690,32 +2705,27 @@ pair<FunctionDefinition const*, ContractDefinition const*> SMTEncoder::functionC
calledExpr = innermostTuple(*calledExpr);
}
auto resolveVirtual = [&](auto const* _ref) -> pair<FunctionDefinition const*, ContractDefinition const*> {
auto resolveVirtual = [&](auto const* _ref) -> FunctionDefinition const* {
VirtualLookup lookup = *_ref->annotation().requiredLookup;
solAssert(_contract || lookup == VirtualLookup::Static, "No contract context provided for function lookup resolution!");
solAssert(_contextContract || lookup == VirtualLookup::Static, "No contract context provided for function lookup resolution!");
auto funDef = dynamic_cast<FunctionDefinition const*>(_ref->annotation().referencedDeclaration);
if (!funDef)
return {funDef, _contract};
ContractDefinition const* contextContract = nullptr;
return funDef;
switch (lookup)
{
case VirtualLookup::Virtual:
funDef = &funDef->resolveVirtual(*_contract);
contextContract = _contract;
break;
return &(funDef->resolveVirtual(*_contextContract));
case VirtualLookup::Super:
{
auto super = _contract->superContract(*_contract);
solAssert(_scopeContract, "");
auto super = _scopeContract->superContract(*_contextContract);
solAssert(super, "Super contract not available.");
funDef = &funDef->resolveVirtual(*_contract, super);
contextContract = super;
break;
return &funDef->resolveVirtual(*_contextContract, super);
}
case VirtualLookup::Static:
contextContract = funDef->annotation().contract;
break;
return funDef;
}
return {funDef, contextContract};
solAssert(false, "");
};
if (Identifier const* fun = dynamic_cast<Identifier const*>(calledExpr))
@@ -2810,11 +2820,12 @@ ModifierDefinition const* SMTEncoder::resolveModifierInvocation(ModifierInvocati
return modifier;
}
vector<FunctionDefinition const*> const& SMTEncoder::contractFunctions(ContractDefinition const& _contract)
set<FunctionDefinition const*, ASTNode::CompareByID> const& SMTEncoder::contractFunctions(ContractDefinition const& _contract)
{
if (!m_contractFunctions.count(&_contract))
{
vector<FunctionDefinition const *> resolvedFunctions = _contract.definedFunctions();
auto const& functions = _contract.definedFunctions();
set<FunctionDefinition const*, ASTNode::CompareByID> resolvedFunctions(begin(functions), end(functions));
for (auto const* base: _contract.annotation().linearizedBaseContracts)
{
if (base == &_contract)
@@ -2836,7 +2847,7 @@ vector<FunctionDefinition const*> const& SMTEncoder::contractFunctions(ContractD
break;
}
if (!overridden)
resolvedFunctions.push_back(baseFunction);
resolvedFunctions.insert(baseFunction);
}
}
m_contractFunctions.emplace(&_contract, move(resolvedFunctions));
@@ -2844,6 +2855,22 @@ vector<FunctionDefinition const*> const& SMTEncoder::contractFunctions(ContractD
return m_contractFunctions.at(&_contract);
}
set<FunctionDefinition const*, ASTNode::CompareByID> const& SMTEncoder::contractFunctionsWithoutVirtual(ContractDefinition const& _contract)
{
if (!m_contractFunctionsWithoutVirtual.count(&_contract))
{
auto allFunctions = contractFunctions(_contract);
for (auto const* base: _contract.annotation().linearizedBaseContracts)
for (auto const* baseFun: base->definedFunctions())
if (!baseFun->isConstructor())
allFunctions.insert(baseFun);
m_contractFunctionsWithoutVirtual.emplace(&_contract, move(allFunctions));
}
return m_contractFunctionsWithoutVirtual.at(&_contract);
}
SourceUnit const* SMTEncoder::sourceUnitContaining(Scopable const& _scopable)
{
for (auto const* s = &_scopable; s; s = dynamic_cast<Scopable const*>(s->scope()))
@@ -2926,9 +2953,9 @@ set<FunctionCall const*> SMTEncoder::collectABICalls(ASTNode const* _node)
return ABIFunctions(_node).abiCalls;
}
void SMTEncoder::createReturnedExpressions(FunctionCall const& _funCall, ContractDefinition const* _contract)
void SMTEncoder::createReturnedExpressions(FunctionCall const& _funCall, ContractDefinition const* _contextContract)
{
auto [funDef, contextContract] = functionCallToDefinition(_funCall, _contract);
auto funDef = functionCallToDefinition(_funCall, currentScopeContract(), _contextContract);
if (!funDef)
return;
@@ -2954,9 +2981,9 @@ void SMTEncoder::createReturnedExpressions(FunctionCall const& _funCall, Contrac
defineExpr(_funCall, currentValue(*returnParams.front()));
}
vector<smtutil::Expression> SMTEncoder::symbolicArguments(FunctionCall const& _funCall, ContractDefinition const* _contract)
vector<smtutil::Expression> SMTEncoder::symbolicArguments(FunctionCall const& _funCall, ContractDefinition const* _contextContract)
{
auto [funDef, contextContract] = functionCallToDefinition(_funCall, _contract);
auto funDef = functionCallToDefinition(_funCall, currentScopeContract(), _contextContract);
solAssert(funDef, "");
vector<smtutil::Expression> args;