Move abstract function check.

This commit is contained in:
chriseth 2018-11-29 17:51:57 +01:00
parent 89cf6a5a38
commit 57a62429c9
4 changed files with 46 additions and 46 deletions

View File

@ -24,6 +24,8 @@
#include <liblangutil/ErrorReporter.h>
#include <boost/range/adaptor/reversed.hpp>
using namespace std;
using namespace dev;
@ -36,6 +38,7 @@ bool ContractLevelChecker::check(ContractDefinition const& _contract)
checkContractDuplicateFunctions(_contract);
checkContractDuplicateEvents(_contract);
checkContractIllegalOverrides(_contract);
checkContractAbstractFunctions(_contract);
return Error::containsOnlyWarnings(m_errorReporter.errors());
}
@ -203,3 +206,45 @@ void ContractLevelChecker::overrideError(FunctionDefinition const& function, Fun
);
}
void ContractLevelChecker::checkContractAbstractFunctions(ContractDefinition const& _contract)
{
// Mapping from name to function definition (exactly one per argument type equality class) and
// flag to indicate whether it is fully implemented.
using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
map<string, vector<FunTypeAndFlag>> functions;
// Search from base to derived
for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
for (FunctionDefinition const* function: contract->definedFunctions())
{
// Take constructors out of overload hierarchy
if (function->isConstructor())
continue;
auto& overloads = functions[function->name()];
FunctionTypePointer funType = make_shared<FunctionType>(*function)->asCallableFunction(false);
auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
{
return funType->hasEqualParameterTypes(*_funAndFlag.first);
});
if (it == overloads.end())
overloads.push_back(make_pair(funType, function->isImplemented()));
else if (it->second)
{
if (!function->isImplemented())
m_errorReporter.typeError(function->location(), "Redeclaring an already implemented function as abstract");
}
else if (function->isImplemented())
it->second = true;
}
// Set to not fully implemented if at least one flag is false.
for (auto const& it: functions)
for (auto const& funAndFlag: it.second)
if (!funAndFlag.second)
{
FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(&funAndFlag.first->declaration());
solAssert(function, "");
_contract.annotation().unimplementedFunctions.push_back(function);
break;
}
}

View File

@ -63,6 +63,7 @@ private:
/// Also stores the direct super function in the AST annotations.
void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super);
void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message);
void checkContractAbstractFunctions(ContractDefinition const& _contract);
langutil::ErrorReporter& m_errorReporter;
};

View File

@ -35,7 +35,6 @@
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <memory>
#include <vector>
@ -96,7 +95,6 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
ASTNode::listAccept(_contract.definedStructs(), *this);
ASTNode::listAccept(_contract.baseContracts(), *this);
checkContractAbstractFunctions(_contract);
checkContractBaseConstructorArguments(_contract);
FunctionDefinition const* function = _contract.constructor();
@ -159,49 +157,6 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
return false;
}
void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _contract)
{
// Mapping from name to function definition (exactly one per argument type equality class) and
// flag to indicate whether it is fully implemented.
using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
map<string, vector<FunTypeAndFlag>> functions;
// Search from base to derived
for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
for (FunctionDefinition const* function: contract->definedFunctions())
{
// Take constructors out of overload hierarchy
if (function->isConstructor())
continue;
auto& overloads = functions[function->name()];
FunctionTypePointer funType = make_shared<FunctionType>(*function)->asCallableFunction(false);
auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
{
return funType->hasEqualParameterTypes(*_funAndFlag.first);
});
if (it == overloads.end())
overloads.push_back(make_pair(funType, function->isImplemented()));
else if (it->second)
{
if (!function->isImplemented())
m_errorReporter.typeError(function->location(), "Redeclaring an already implemented function as abstract");
}
else if (function->isImplemented())
it->second = true;
}
// Set to not fully implemented if at least one flag is false.
for (auto const& it: functions)
for (auto const& funAndFlag: it.second)
if (!funAndFlag.second)
{
FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(&funAndFlag.first->declaration());
solAssert(function, "");
_contract.annotation().unimplementedFunctions.push_back(function);
break;
}
}
void TypeChecker::checkContractBaseConstructorArguments(ContractDefinition const& _contract)
{
vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;

View File

@ -66,7 +66,6 @@ public:
private:
bool visit(ContractDefinition const& _contract) override;
void checkContractAbstractFunctions(ContractDefinition const& _contract);
void checkContractBaseConstructorArguments(ContractDefinition const& _contract);
void annotateBaseConstructorArguments(
ContractDefinition const& _currentContract,