mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Introduce function call statements.
This commit is contained in:
parent
0000bb0eea
commit
0e15a794d8
@ -44,6 +44,7 @@
|
|||||||
MACRO(AssignmentStmtGenerator) SEP \
|
MACRO(AssignmentStmtGenerator) SEP \
|
||||||
MACRO(BlockStmtGenerator) SEP \
|
MACRO(BlockStmtGenerator) SEP \
|
||||||
MACRO(ContractGenerator) SEP \
|
MACRO(ContractGenerator) SEP \
|
||||||
|
MACRO(FunctionCallGenerator) SEP \
|
||||||
MACRO(FunctionGenerator) SEP \
|
MACRO(FunctionGenerator) SEP \
|
||||||
MACRO(ImportGenerator) SEP \
|
MACRO(ImportGenerator) SEP \
|
||||||
MACRO(PragmaGenerator) SEP \
|
MACRO(PragmaGenerator) SEP \
|
||||||
|
@ -165,6 +165,17 @@ string PragmaGenerator::visit()
|
|||||||
return boost::algorithm::join(pragmas, "\n") + "\n";
|
return boost::algorithm::join(pragmas, "\n") + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SourceState::resolveImports(map<SolidityTypePtr, string> _importedSymbols)
|
||||||
|
{
|
||||||
|
for (auto const& item: _importedSymbols)
|
||||||
|
exports.emplace(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceState::mergeFunctionState(set<shared_ptr<FunctionState>> _importedFreeFunctions)
|
||||||
|
{
|
||||||
|
freeFunctions += _importedFreeFunctions;
|
||||||
|
}
|
||||||
|
|
||||||
string ImportGenerator::visit()
|
string ImportGenerator::visit()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -189,6 +200,9 @@ string ImportGenerator::visit()
|
|||||||
state->sourceUnitState[state->currentPath()]->resolveImports(
|
state->sourceUnitState[state->currentPath()]->resolveImports(
|
||||||
state->sourceUnitState[importPath]->exports
|
state->sourceUnitState[importPath]->exports
|
||||||
);
|
);
|
||||||
|
state->sourceUnitState[state->currentPath()]->mergeFunctionState(
|
||||||
|
state->sourceUnitState[importPath]->freeFunctions
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
@ -205,10 +219,12 @@ string ContractGenerator::visit()
|
|||||||
ScopeGuard reset([&]() {
|
ScopeGuard reset([&]() {
|
||||||
mutator->generator<FunctionGenerator>()->scope(true);
|
mutator->generator<FunctionGenerator>()->scope(true);
|
||||||
state->unindent();
|
state->unindent();
|
||||||
|
state->exitContract();
|
||||||
});
|
});
|
||||||
auto set = [&]() {
|
auto set = [&]() {
|
||||||
state->indent();
|
state->indent();
|
||||||
mutator->generator<FunctionGenerator>()->scope(false);
|
mutator->generator<FunctionGenerator>()->scope(false);
|
||||||
|
state->enterContract();
|
||||||
};
|
};
|
||||||
ostringstream os;
|
ostringstream os;
|
||||||
string inheritance;
|
string inheritance;
|
||||||
@ -286,7 +302,8 @@ void StatementGenerator::setup()
|
|||||||
{
|
{
|
||||||
addGenerators({
|
addGenerators({
|
||||||
{mutator->generator<BlockStmtGenerator>(), 1},
|
{mutator->generator<BlockStmtGenerator>(), 1},
|
||||||
{mutator->generator<AssignmentStmtGenerator>(), 1}
|
{mutator->generator<AssignmentStmtGenerator>(), 1},
|
||||||
|
{mutator->generator<FunctionCallGenerator>(), 1}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +326,7 @@ string StatementGenerator::visit()
|
|||||||
if (uRandDist->likely(child.second + 1))
|
if (uRandDist->likely(child.second + 1))
|
||||||
{
|
{
|
||||||
os << std::visit(GenericVisitor{
|
os << std::visit(GenericVisitor{
|
||||||
[&](auto const& _item) { return _item->generate(); }
|
[](auto const& _item) { return _item->generate(); }
|
||||||
}, child.first);
|
}, child.first);
|
||||||
if (holds_alternative<shared_ptr<BlockStmtGenerator>>(child.first) &&
|
if (holds_alternative<shared_ptr<BlockStmtGenerator>>(child.first) &&
|
||||||
generateUncheckedBlock
|
generateUncheckedBlock
|
||||||
@ -358,7 +375,7 @@ string FunctionGenerator::visit()
|
|||||||
{
|
{
|
||||||
string visibility;
|
string visibility;
|
||||||
string name = state->newFunction();
|
string name = state->newFunction();
|
||||||
state->updateFunction(name);
|
state->updateFunction(name, m_freeFunction);
|
||||||
if (!m_freeFunction)
|
if (!m_freeFunction)
|
||||||
visibility = "external";
|
visibility = "external";
|
||||||
|
|
||||||
@ -385,6 +402,10 @@ string FunctionGenerator::visit()
|
|||||||
// Make sure block stmt generator does not output an unchecked block
|
// Make sure block stmt generator does not output an unchecked block
|
||||||
mutator->generator<BlockStmtGenerator>()->unchecked(false);
|
mutator->generator<BlockStmtGenerator>()->unchecked(false);
|
||||||
block << visitChildren();
|
block << visitChildren();
|
||||||
|
if (m_freeFunction)
|
||||||
|
state->currentSourceState()->addFreeFunction(state->currentFunctionState());
|
||||||
|
else
|
||||||
|
state->currentContractState()->addFunction(state->currentFunctionState());
|
||||||
// Since visitChildren() may not visit block stmt, we default to an empty
|
// Since visitChildren() may not visit block stmt, we default to an empty
|
||||||
// block.
|
// block.
|
||||||
if (block.str().empty())
|
if (block.str().empty())
|
||||||
@ -420,22 +441,9 @@ pair<SolidityTypePtr, string> ExpressionGenerator::randomLValueExpression()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<pair<SolidityTypePtr, string>> ExpressionGenerator::expression()
|
optional<pair<SolidityTypePtr, string>> ExpressionGenerator::lValueExpression(
|
||||||
{
|
pair<SolidityTypePtr, string> _typeName
|
||||||
auto currentFunctionState = state->currentFunctionState();
|
)
|
||||||
// TODO: Remove this barrier once we support more expression types.
|
|
||||||
if (currentFunctionState->inputs.empty() && currentFunctionState->outputs.empty())
|
|
||||||
return nullopt;
|
|
||||||
return randomLValueExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
pair<SolidityTypePtr, string> ExpressionGenerator::literal(SolidityTypePtr _type)
|
|
||||||
{
|
|
||||||
string literalValue = visit(LiteralGenerator{state}, _type);
|
|
||||||
return pair(_type, literalValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
optional<pair<SolidityTypePtr, string>> ExpressionGenerator::expression(pair<SolidityTypePtr, string> _typeName)
|
|
||||||
{
|
{
|
||||||
// Filter non-identical variables of the same type.
|
// Filter non-identical variables of the same type.
|
||||||
auto liveTypedVariables = state->currentFunctionState()->inputs |
|
auto liveTypedVariables = state->currentFunctionState()->inputs |
|
||||||
@ -453,6 +461,30 @@ optional<pair<SolidityTypePtr, string>> ExpressionGenerator::expression(pair<Sol
|
|||||||
}) |
|
}) |
|
||||||
ranges::to<vector<pair<SolidityTypePtr, string>>>();
|
ranges::to<vector<pair<SolidityTypePtr, string>>>();
|
||||||
if (liveTypedVariables.empty())
|
if (liveTypedVariables.empty())
|
||||||
|
return nullopt;
|
||||||
|
else
|
||||||
|
return liveTypedVariables[state->uRandDist->distributionOneToN(liveTypedVariables.size()) - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<pair<SolidityTypePtr, string>> ExpressionGenerator::expression()
|
||||||
|
{
|
||||||
|
auto currentFunctionState = state->currentFunctionState();
|
||||||
|
// TODO: Remove this barrier once we support more expression types.
|
||||||
|
if (currentFunctionState->inputs.empty() && currentFunctionState->outputs.empty())
|
||||||
|
return nullopt;
|
||||||
|
return randomLValueExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
pair<SolidityTypePtr, string> ExpressionGenerator::literal(SolidityTypePtr _type)
|
||||||
|
{
|
||||||
|
string literalValue = visit(LiteralGenerator{state}, _type);
|
||||||
|
return pair(_type, literalValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<pair<SolidityTypePtr, string>> ExpressionGenerator::expression(pair<SolidityTypePtr, string> _typeName)
|
||||||
|
{
|
||||||
|
auto varRef = lValueExpression(_typeName);
|
||||||
|
if (!varRef.has_value())
|
||||||
{
|
{
|
||||||
// TODO: Generate literals for contract and function types.
|
// TODO: Generate literals for contract and function types.
|
||||||
if (!(holds_alternative<shared_ptr<FunctionType>>(_typeName.first) || holds_alternative<shared_ptr<ContractType>>(_typeName.first)))
|
if (!(holds_alternative<shared_ptr<FunctionType>>(_typeName.first) || holds_alternative<shared_ptr<ContractType>>(_typeName.first)))
|
||||||
@ -460,7 +492,8 @@ optional<pair<SolidityTypePtr, string>> ExpressionGenerator::expression(pair<Sol
|
|||||||
else
|
else
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
return liveTypedVariables[state->uRandDist->distributionOneToN(liveTypedVariables.size()) - 1];
|
else
|
||||||
|
return varRef.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
string LiteralGenerator::operator()(shared_ptr<AddressType> const&)
|
string LiteralGenerator::operator()(shared_ptr<AddressType> const&)
|
||||||
@ -574,7 +607,7 @@ SolidityTypePtr TypeProvider::type()
|
|||||||
case Type::ADDRESS:
|
case Type::ADDRESS:
|
||||||
return make_shared<AddressType>();
|
return make_shared<AddressType>();
|
||||||
case Type::FUNCTION:
|
case Type::FUNCTION:
|
||||||
return make_shared<FunctionType>();
|
return make_shared<FunctionType>(false);
|
||||||
case Type::CONTRACT:
|
case Type::CONTRACT:
|
||||||
if (state->sourceUnitState[state->currentPath()]->contractType())
|
if (state->sourceUnitState[state->currentPath()]->contractType())
|
||||||
return state->sourceUnitState[state->currentPath()]->randomContractType();
|
return state->sourceUnitState[state->currentPath()]->randomContractType();
|
||||||
@ -584,6 +617,150 @@ SolidityTypePtr TypeProvider::type()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string FunctionCallGenerator::lhs(vector<pair<SolidityTypePtr, string>> _functionReturnTypeNames)
|
||||||
|
{
|
||||||
|
ExpressionGenerator exprGen{state};
|
||||||
|
ostringstream callStmtLhs;
|
||||||
|
|
||||||
|
auto assignToVars = _functionReturnTypeNames |
|
||||||
|
ranges::views::transform([&exprGen](auto const& _item) -> pair<bool, optional<pair<SolidityTypePtr, string>>> {
|
||||||
|
auto e = exprGen.lValueExpression(_item);
|
||||||
|
if (e.has_value())
|
||||||
|
return {true, e.value()};
|
||||||
|
else
|
||||||
|
return {false, nullopt};
|
||||||
|
});
|
||||||
|
bool useExistingVars = ranges::all_of(
|
||||||
|
assignToVars,
|
||||||
|
[](auto const& _item) -> bool { return _item.first; }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (useExistingVars)
|
||||||
|
{
|
||||||
|
auto vars = assignToVars |
|
||||||
|
ranges::views::transform([](auto const& _item) { return _item.second.value().second; }) |
|
||||||
|
ranges::to<vector<string>>();
|
||||||
|
callStmtLhs << "("
|
||||||
|
<< boost::algorithm::join(vars, ",")
|
||||||
|
<< ") = ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto newVars = _functionReturnTypeNames |
|
||||||
|
ranges::views::transform([&](auto const& _item) -> string {
|
||||||
|
state->currentFunctionState()->addLocal(_item.first);
|
||||||
|
string varName = state->currentFunctionState()->locals.back().second;
|
||||||
|
return std::visit(
|
||||||
|
GenericVisitor{[](auto const& _it) { return _it->toString(); }},
|
||||||
|
_item.first
|
||||||
|
) +
|
||||||
|
" " +
|
||||||
|
varName;
|
||||||
|
}) |
|
||||||
|
ranges::to<vector<string>>();
|
||||||
|
callStmtLhs << "("
|
||||||
|
<< boost::algorithm::join(newVars, ", ")
|
||||||
|
<< ") = ";
|
||||||
|
}
|
||||||
|
return callStmtLhs.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<string> FunctionCallGenerator::rhs(vector<pair<SolidityTypePtr, string>> _functionInputTypeNames)
|
||||||
|
{
|
||||||
|
ExpressionGenerator exprGen{state};
|
||||||
|
ostringstream callStmtRhs;
|
||||||
|
|
||||||
|
auto inputArguments = _functionInputTypeNames |
|
||||||
|
ranges::views::transform([&exprGen](auto const& _item) -> pair<bool, optional<pair<SolidityTypePtr, string>>>
|
||||||
|
{
|
||||||
|
auto e = exprGen.expression(_item);
|
||||||
|
if (e.has_value())
|
||||||
|
return {true, e.value()};
|
||||||
|
else
|
||||||
|
return {false, nullopt};
|
||||||
|
});
|
||||||
|
bool inputArgsValid = ranges::all_of(
|
||||||
|
inputArguments,
|
||||||
|
[](auto const& _item) -> bool { return _item.first; }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (inputArgsValid)
|
||||||
|
{
|
||||||
|
auto vars = inputArguments |
|
||||||
|
ranges::views::transform([](auto const& _item) { return _item.second.value().second; }) |
|
||||||
|
ranges::to<vector<string>>();
|
||||||
|
callStmtRhs << boost::algorithm::join(vars, ",");
|
||||||
|
return callStmtRhs.str();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string FunctionCallGenerator::callStmt(shared_ptr<FunctionState> _callee)
|
||||||
|
{
|
||||||
|
ostringstream callStmtStream;
|
||||||
|
string lhsExpr;
|
||||||
|
string rhsExpr;
|
||||||
|
bool callValid = true;
|
||||||
|
|
||||||
|
// Create lhs expression only if function outputs non-zero return values.
|
||||||
|
if (!_callee->outputs.empty())
|
||||||
|
lhsExpr = lhs(_callee->outputs);
|
||||||
|
|
||||||
|
// Create arguments only if function contains non-zero input parameters.
|
||||||
|
if (!_callee->inputs.empty())
|
||||||
|
{
|
||||||
|
auto callRhs = rhs(_callee->inputs);
|
||||||
|
// Arguments may not be found for function and contract types. In this
|
||||||
|
// case, do not make the call.
|
||||||
|
if (callRhs.has_value())
|
||||||
|
rhsExpr = (_callee->type->functionScope() ? "" : "this.") + _callee->name + "(" + callRhs.value() + ");";
|
||||||
|
else
|
||||||
|
callValid = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rhsExpr = (_callee->type->functionScope() ? "" : "this.") + _callee->name + "();";
|
||||||
|
|
||||||
|
if (callValid)
|
||||||
|
callStmtStream << indentation()
|
||||||
|
<< lhsExpr
|
||||||
|
<< rhsExpr;
|
||||||
|
callStmtStream << "\n";
|
||||||
|
return callStmtStream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string FunctionCallGenerator::visit()
|
||||||
|
{
|
||||||
|
// // TODO: Generalise call to varargs function
|
||||||
|
// for (auto const& f: state->currentFunctionState()->inputs)
|
||||||
|
// if (holds_alternative<shared_ptr<FunctionType>>(f.first))
|
||||||
|
// return indentation() + f.second + "();\n";
|
||||||
|
|
||||||
|
// Consolidate available functions
|
||||||
|
auto availableFunctions = state->currentSourceState()->freeFunctions;
|
||||||
|
if (state->insideContract)
|
||||||
|
availableFunctions += state->currentContractState()->functions;
|
||||||
|
if (availableFunctions.empty())
|
||||||
|
return "\n";
|
||||||
|
|
||||||
|
shared_ptr<FunctionState> callee;
|
||||||
|
if (availableFunctions.size() > 1)
|
||||||
|
{
|
||||||
|
for (auto const& i: availableFunctions)
|
||||||
|
if (uRandDist->probable(availableFunctions.size()))
|
||||||
|
callee = i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
callee = *availableFunctions.begin();
|
||||||
|
|
||||||
|
if (callee)
|
||||||
|
return callStmt(callee);
|
||||||
|
else
|
||||||
|
return "\n";
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
shared_ptr<T> SolidityGenerator::generator()
|
shared_ptr<T> SolidityGenerator::generator()
|
||||||
{
|
{
|
||||||
|
@ -112,15 +112,6 @@ struct UniformRandomDistribution
|
|||||||
std::unique_ptr<RandomEngine> randomEngine;
|
std::unique_ptr<RandomEngine> randomEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContractState
|
|
||||||
{
|
|
||||||
explicit ContractState(std::shared_ptr<UniformRandomDistribution> _urd):
|
|
||||||
uRandDist(std::move(_urd))
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::shared_ptr<UniformRandomDistribution> uRandDist;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SolType
|
class SolType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -302,7 +293,10 @@ public:
|
|||||||
class FunctionType: public SolType
|
class FunctionType: public SolType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FunctionType() = default;
|
FunctionType(bool _freeFunction)
|
||||||
|
{
|
||||||
|
freeFunction = _freeFunction;
|
||||||
|
}
|
||||||
~FunctionType() override
|
~FunctionType() override
|
||||||
{
|
{
|
||||||
inputs.clear();
|
inputs.clear();
|
||||||
@ -319,6 +313,11 @@ public:
|
|||||||
outputs.emplace_back(_output);
|
outputs.emplace_back(_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool functionScope()
|
||||||
|
{
|
||||||
|
return freeFunction;
|
||||||
|
}
|
||||||
|
|
||||||
std::string toString() override;
|
std::string toString() override;
|
||||||
bool operator==(FunctionType const& _rhs)
|
bool operator==(FunctionType const& _rhs)
|
||||||
{
|
{
|
||||||
@ -333,20 +332,30 @@ public:
|
|||||||
|
|
||||||
std::vector<SolidityTypePtr> inputs;
|
std::vector<SolidityTypePtr> inputs;
|
||||||
std::vector<SolidityTypePtr> outputs;
|
std::vector<SolidityTypePtr> outputs;
|
||||||
|
bool freeFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Forward declaration
|
/// Forward declaration
|
||||||
struct TestState;
|
struct TestState;
|
||||||
|
struct FunctionState;
|
||||||
|
|
||||||
struct SourceState
|
struct SourceState
|
||||||
{
|
{
|
||||||
explicit SourceState(std::shared_ptr<UniformRandomDistribution> _urd):
|
explicit SourceState(
|
||||||
|
std::shared_ptr<UniformRandomDistribution> _urd,
|
||||||
|
std::string _sourceName
|
||||||
|
):
|
||||||
uRandDist(std::move(_urd)),
|
uRandDist(std::move(_urd)),
|
||||||
importedSources({})
|
importedSources({}),
|
||||||
|
sourceName(_sourceName)
|
||||||
{}
|
{}
|
||||||
void addFreeFunction(std::string& _functionName)
|
void addFreeFunction(std::string& _functionName)
|
||||||
{
|
{
|
||||||
exports[std::make_shared<FunctionType>()] = _functionName;
|
exports[std::make_shared<FunctionType>(true)] = _functionName;
|
||||||
|
}
|
||||||
|
void addFreeFunction(std::shared_ptr<FunctionState> _state)
|
||||||
|
{
|
||||||
|
freeFunctions.emplace(_state);
|
||||||
}
|
}
|
||||||
bool freeFunction(std::string const& _functionName)
|
bool freeFunction(std::string const& _functionName)
|
||||||
{
|
{
|
||||||
@ -387,11 +396,9 @@ struct SourceState
|
|||||||
{
|
{
|
||||||
importedSources.emplace(_sourcePath);
|
importedSources.emplace(_sourcePath);
|
||||||
}
|
}
|
||||||
void resolveImports(std::map<SolidityTypePtr, std::string> _imports)
|
void resolveImports(std::map<SolidityTypePtr, std::string> _importedSymbols);
|
||||||
{
|
void mergeFunctionState(std::set<std::shared_ptr<FunctionState>> _importedFreeFunctions);
|
||||||
for (auto const& item: _imports)
|
|
||||||
exports.emplace(item);
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool sourcePathImported(std::string const& _sourcePath) const
|
[[nodiscard]] bool sourcePathImported(std::string const& _sourcePath) const
|
||||||
{
|
{
|
||||||
return importedSources.count(_sourcePath);
|
return importedSources.count(_sourcePath);
|
||||||
@ -399,12 +406,16 @@ struct SourceState
|
|||||||
~SourceState()
|
~SourceState()
|
||||||
{
|
{
|
||||||
importedSources.clear();
|
importedSources.clear();
|
||||||
|
freeFunctions.clear();
|
||||||
|
exports.clear();
|
||||||
}
|
}
|
||||||
/// Prints source state to @param _os.
|
/// Prints source state to @param _os.
|
||||||
void print(std::ostream& _os) const;
|
void print(std::ostream& _os) const;
|
||||||
std::shared_ptr<UniformRandomDistribution> uRandDist;
|
std::shared_ptr<UniformRandomDistribution> uRandDist;
|
||||||
std::set<std::string> importedSources;
|
std::set<std::string> importedSources;
|
||||||
std::map<SolidityTypePtr, std::string> exports;
|
std::map<SolidityTypePtr, std::string> exports;
|
||||||
|
std::set<std::shared_ptr<FunctionState>> freeFunctions;
|
||||||
|
std::string sourceName;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FunctionState
|
struct FunctionState
|
||||||
@ -414,27 +425,63 @@ struct FunctionState
|
|||||||
INPUT,
|
INPUT,
|
||||||
OUTPUT
|
OUTPUT
|
||||||
};
|
};
|
||||||
FunctionState() = default;
|
FunctionState(std::string _functionName, bool _freeFunction):
|
||||||
|
numInputs(0),
|
||||||
|
numOutpus(0),
|
||||||
|
numLocals(0),
|
||||||
|
name(_functionName)
|
||||||
|
{
|
||||||
|
type = std::make_shared<FunctionType>(_freeFunction);
|
||||||
|
}
|
||||||
~FunctionState()
|
~FunctionState()
|
||||||
{
|
{
|
||||||
inputs.clear();
|
inputs.clear();
|
||||||
outputs.clear();
|
outputs.clear();
|
||||||
|
locals.clear();
|
||||||
}
|
}
|
||||||
using TypeId = std::pair<SolidityTypePtr, std::string>;
|
|
||||||
void addInput(SolidityTypePtr _input)
|
void addInput(SolidityTypePtr _input)
|
||||||
{
|
{
|
||||||
inputs.emplace(_input, "i" + std::to_string(numInputs++));
|
inputs.emplace_back(_input, "i" + std::to_string(numInputs++));
|
||||||
|
type->addInput(_input);
|
||||||
}
|
}
|
||||||
void addOutput(SolidityTypePtr _output)
|
void addOutput(SolidityTypePtr _output)
|
||||||
{
|
{
|
||||||
outputs.emplace(_output, "o" + std::to_string(numOutpus++));
|
outputs.emplace_back(_output, "o" + std::to_string(numOutpus++));
|
||||||
|
type->addOutput(_output);
|
||||||
|
}
|
||||||
|
void addLocal(SolidityTypePtr _local)
|
||||||
|
{
|
||||||
|
locals.emplace_back(_local, "l" + std::to_string(numLocals++));
|
||||||
}
|
}
|
||||||
std::string params(Params _p);
|
std::string params(Params _p);
|
||||||
|
|
||||||
std::map<SolidityTypePtr, std::string> inputs;
|
std::vector<std::pair<SolidityTypePtr, std::string>> inputs;
|
||||||
std::map<SolidityTypePtr, std::string> outputs;
|
std::vector<std::pair<SolidityTypePtr, std::string>> outputs;
|
||||||
unsigned numInputs = 0;
|
std::vector<std::pair<SolidityTypePtr, std::string>> locals;
|
||||||
unsigned numOutpus = 0;
|
std::shared_ptr<FunctionType> type;
|
||||||
|
unsigned numInputs;
|
||||||
|
unsigned numOutpus;
|
||||||
|
unsigned numLocals;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ContractState
|
||||||
|
{
|
||||||
|
explicit ContractState(
|
||||||
|
std::shared_ptr<UniformRandomDistribution> _urd,
|
||||||
|
std::string _contractName
|
||||||
|
):
|
||||||
|
uRandDist(std::move(_urd)),
|
||||||
|
name(_contractName)
|
||||||
|
{}
|
||||||
|
void addFunction(std::shared_ptr<FunctionState> _function)
|
||||||
|
{
|
||||||
|
functions.emplace(_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::shared_ptr<FunctionState>> functions;
|
||||||
|
std::shared_ptr<UniformRandomDistribution> uRandDist;
|
||||||
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestState
|
struct TestState
|
||||||
@ -449,28 +496,29 @@ struct TestState
|
|||||||
numSourceUnits(0),
|
numSourceUnits(0),
|
||||||
numContracts(0),
|
numContracts(0),
|
||||||
numFunctions(0),
|
numFunctions(0),
|
||||||
indentationLevel(0)
|
indentationLevel(0),
|
||||||
|
insideContract(false)
|
||||||
{}
|
{}
|
||||||
/// Adds @param _path to @name sourceUnitPaths updates
|
/// Adds @param _path to @name sourceUnitPaths updates
|
||||||
/// @name currentSourceUnitPath.
|
/// @name currentSourceUnitPath.
|
||||||
void addSourceUnit(std::string const& _path)
|
void addSourceUnit(std::string const& _path)
|
||||||
{
|
{
|
||||||
sourceUnitState.emplace(_path, std::make_shared<SourceState>(uRandDist));
|
sourceUnitState.emplace(_path, std::make_shared<SourceState>(uRandDist, _path));
|
||||||
currentSourceUnitPath = _path;
|
currentSourceUnitPath = _path;
|
||||||
}
|
}
|
||||||
/// Adds @param _name to @name contractState updates
|
/// Adds @param _name to @name contractState updates
|
||||||
/// @name currentContract.
|
/// @name currentContract.
|
||||||
void addContract(std::string const& _name)
|
void addContract(std::string const& _name)
|
||||||
{
|
{
|
||||||
contractState.emplace(_name, std::make_shared<ContractState>(uRandDist));
|
contractState.emplace(_name, std::make_shared<ContractState>(uRandDist, _name));
|
||||||
sourceUnitState[currentSourceUnitPath]->exports[
|
sourceUnitState[currentSourceUnitPath]->exports[
|
||||||
std::make_shared<ContractType>(_name)
|
std::make_shared<ContractType>(_name)
|
||||||
] = _name;
|
] = _name;
|
||||||
currentContract = _name;
|
currentContract = _name;
|
||||||
}
|
}
|
||||||
void addFunction(std::string const& _name)
|
void addFunction(std::string const& _name, bool _freeFunction)
|
||||||
{
|
{
|
||||||
functionState.emplace(_name, std::make_shared<FunctionState>());
|
functionState.emplace(_name, std::make_shared<FunctionState>(_name, _freeFunction));
|
||||||
currentFunction = _name;
|
currentFunction = _name;
|
||||||
}
|
}
|
||||||
std::shared_ptr<FunctionState> currentFunctionState()
|
std::shared_ptr<FunctionState> currentFunctionState()
|
||||||
@ -483,6 +531,11 @@ struct TestState
|
|||||||
std::string currentSource = currentPath();
|
std::string currentSource = currentPath();
|
||||||
return sourceUnitState[currentSource];
|
return sourceUnitState[currentSource];
|
||||||
}
|
}
|
||||||
|
std::shared_ptr<ContractState> currentContractState()
|
||||||
|
{
|
||||||
|
std::string contract = currentContractName();
|
||||||
|
return contractState[contract];
|
||||||
|
}
|
||||||
/// Returns true if @name sourceUnitPaths is empty,
|
/// Returns true if @name sourceUnitPaths is empty,
|
||||||
/// false otherwise.
|
/// false otherwise.
|
||||||
[[nodiscard]] bool empty() const
|
[[nodiscard]] bool empty() const
|
||||||
@ -520,6 +573,11 @@ struct TestState
|
|||||||
solAssert(numFunctions > 0, "");
|
solAssert(numFunctions > 0, "");
|
||||||
return currentFunction;
|
return currentFunction;
|
||||||
}
|
}
|
||||||
|
std::string currentContractName() const
|
||||||
|
{
|
||||||
|
solAssert(numContracts > 0, "");
|
||||||
|
return currentContract;
|
||||||
|
}
|
||||||
/// Adds @param _path to list of source paths in global test
|
/// Adds @param _path to list of source paths in global test
|
||||||
/// state and increments @name m_numSourceUnits.
|
/// state and increments @name m_numSourceUnits.
|
||||||
void updateSourcePath(std::string const& _path)
|
void updateSourcePath(std::string const& _path)
|
||||||
@ -534,9 +592,9 @@ struct TestState
|
|||||||
addContract(_name);
|
addContract(_name);
|
||||||
numContracts++;
|
numContracts++;
|
||||||
}
|
}
|
||||||
void updateFunction(std::string const& _name)
|
void updateFunction(std::string const& _name, bool _freeFunction)
|
||||||
{
|
{
|
||||||
addFunction(_name);
|
addFunction(_name, _freeFunction);
|
||||||
numFunctions++;
|
numFunctions++;
|
||||||
}
|
}
|
||||||
void addSource()
|
void addSource()
|
||||||
@ -554,6 +612,14 @@ struct TestState
|
|||||||
{
|
{
|
||||||
--indentationLevel;
|
--indentationLevel;
|
||||||
}
|
}
|
||||||
|
void enterContract()
|
||||||
|
{
|
||||||
|
insideContract = true;
|
||||||
|
}
|
||||||
|
void exitContract()
|
||||||
|
{
|
||||||
|
insideContract = false;
|
||||||
|
}
|
||||||
~TestState()
|
~TestState()
|
||||||
{
|
{
|
||||||
sourceUnitState.clear();
|
sourceUnitState.clear();
|
||||||
@ -590,6 +656,8 @@ struct TestState
|
|||||||
size_t numFunctions;
|
size_t numFunctions;
|
||||||
/// Indentation level
|
/// Indentation level
|
||||||
unsigned indentationLevel;
|
unsigned indentationLevel;
|
||||||
|
/// Contract scope
|
||||||
|
bool insideContract;
|
||||||
/// Source name prefix
|
/// Source name prefix
|
||||||
std::string const sourceUnitNamePrefix = "su";
|
std::string const sourceUnitNamePrefix = "su";
|
||||||
/// Contract name prefix
|
/// Contract name prefix
|
||||||
@ -668,10 +736,15 @@ struct ExpressionGenerator
|
|||||||
TYPEMAX
|
TYPEMAX
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<std::pair<SolidityTypePtr, std::string>> expression(std::pair<SolidityTypePtr, std::string> _typeName);
|
std::optional<std::pair<SolidityTypePtr, std::string>> expression(
|
||||||
|
std::pair<SolidityTypePtr, std::string> _typeName
|
||||||
|
);
|
||||||
std::pair<SolidityTypePtr, std::string> literal(SolidityTypePtr _type);
|
std::pair<SolidityTypePtr, std::string> literal(SolidityTypePtr _type);
|
||||||
std::optional<std::pair<SolidityTypePtr, std::string>> expression();
|
std::optional<std::pair<SolidityTypePtr, std::string>> expression();
|
||||||
std::pair<SolidityTypePtr, std::string> randomLValueExpression();
|
std::pair<SolidityTypePtr, std::string> randomLValueExpression();
|
||||||
|
std::optional<std::pair<SolidityTypePtr, std::string>> lValueExpression(
|
||||||
|
std::pair<SolidityTypePtr, std::string> _typeName
|
||||||
|
);
|
||||||
|
|
||||||
std::shared_ptr<TestState> state;
|
std::shared_ptr<TestState> state;
|
||||||
};
|
};
|
||||||
@ -924,6 +997,23 @@ private:
|
|||||||
static constexpr size_t s_uncheckedInvProb = 13;
|
static constexpr size_t s_uncheckedInvProb = 13;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FunctionCallGenerator: public GeneratorBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FunctionCallGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||||
|
GeneratorBase(std::move(_mutator))
|
||||||
|
{}
|
||||||
|
std::string visit() override;
|
||||||
|
std::string name() override
|
||||||
|
{
|
||||||
|
return "Function call generator";
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string lhs(std::vector<std::pair<SolidityTypePtr, std::string>> _functionReturnTypeNames);
|
||||||
|
std::optional<std::string> rhs(std::vector<std::pair<SolidityTypePtr, std::string>> _functionInputTypeNames);
|
||||||
|
std::string callStmt(std::shared_ptr<FunctionState> _callee);
|
||||||
|
};
|
||||||
|
|
||||||
class SolidityGenerator: public std::enable_shared_from_this<SolidityGenerator>
|
class SolidityGenerator: public std::enable_shared_from_this<SolidityGenerator>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Loading…
Reference in New Issue
Block a user