mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
CFGNode: For function calls store a pointer to a resolved function definition rather than the FunctionCall AST node
This commit is contained in:
parent
2f33105d11
commit
fbe1181517
@ -300,8 +300,7 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
|
|||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
ASTNode::listAccept(_functionCall.arguments(), *this);
|
ASTNode::listAccept(_functionCall.arguments(), *this);
|
||||||
|
|
||||||
solAssert(!m_currentNode->functionCall);
|
m_currentNode->functionDefinition = ASTNode::resolveFunctionCall(_functionCall, m_contract);
|
||||||
m_currentNode->functionCall = &_functionCall;
|
|
||||||
|
|
||||||
auto nextNode = newLabel();
|
auto nextNode = newLabel();
|
||||||
|
|
||||||
@ -318,6 +317,8 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
bool ControlFlowBuilder::visit(ModifierInvocation const& _modifierInvocation)
|
bool ControlFlowBuilder::visit(ModifierInvocation const& _modifierInvocation)
|
||||||
{
|
{
|
||||||
|
solAssert(m_contract, "Free functions cannot have modifiers");
|
||||||
|
|
||||||
if (auto arguments = _modifierInvocation.arguments())
|
if (auto arguments = _modifierInvocation.arguments())
|
||||||
for (auto& argument: *arguments)
|
for (auto& argument: *arguments)
|
||||||
appendControlFlow(*argument);
|
appendControlFlow(*argument);
|
||||||
|
@ -38,14 +38,14 @@ public:
|
|||||||
static std::unique_ptr<FunctionFlow> createFunctionFlow(
|
static std::unique_ptr<FunctionFlow> createFunctionFlow(
|
||||||
CFG::NodeContainer& _nodeContainer,
|
CFG::NodeContainer& _nodeContainer,
|
||||||
FunctionDefinition const& _function,
|
FunctionDefinition const& _function,
|
||||||
ContractDefinition const* _contract = nullptr
|
ContractDefinition const* _contract
|
||||||
);
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ControlFlowBuilder(
|
explicit ControlFlowBuilder(
|
||||||
CFG::NodeContainer& _nodeContainer,
|
CFG::NodeContainer& _nodeContainer,
|
||||||
FunctionFlow const& _functionFlow,
|
FunctionFlow const& _functionFlow,
|
||||||
ContractDefinition const* _contract = nullptr
|
ContractDefinition const* _contract
|
||||||
);
|
);
|
||||||
|
|
||||||
// Visits for constructing the control flow.
|
// Visits for constructing the control flow.
|
||||||
|
@ -34,7 +34,11 @@ bool CFG::constructFlow(ASTNode const& _astRoot)
|
|||||||
bool CFG::visit(FunctionDefinition const& _function)
|
bool CFG::visit(FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
if (_function.isImplemented() && _function.isFree())
|
if (_function.isImplemented() && _function.isFree())
|
||||||
m_functionControlFlow[{nullptr, &_function}] = ControlFlowBuilder::createFunctionFlow(m_nodeContainer, _function);
|
m_functionControlFlow[{nullptr, &_function}] = ControlFlowBuilder::createFunctionFlow(
|
||||||
|
m_nodeContainer,
|
||||||
|
_function,
|
||||||
|
nullptr /* _contract */
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +98,8 @@ struct CFGNode
|
|||||||
std::vector<CFGNode*> entries;
|
std::vector<CFGNode*> entries;
|
||||||
/// Exit nodes. All CFG nodes to which control flow may continue after this node.
|
/// Exit nodes. All CFG nodes to which control flow may continue after this node.
|
||||||
std::vector<CFGNode*> exits;
|
std::vector<CFGNode*> exits;
|
||||||
/// Function call done by this node
|
/// Resolved definition of the function called by this node
|
||||||
FunctionCall const* functionCall = nullptr;
|
FunctionDefinition const* functionDefinition = nullptr;
|
||||||
|
|
||||||
/// Variable occurrences in the node.
|
/// Variable occurrences in the node.
|
||||||
std::vector<VariableOccurrence> variableOccurrences;
|
std::vector<VariableOccurrence> variableOccurrences;
|
||||||
// Source location of this control flow block.
|
// Source location of this control flow block.
|
||||||
|
@ -81,27 +81,23 @@ void ControlFlowRevertPruner::findRevertStates()
|
|||||||
if (_node == functionFlow.exit)
|
if (_node == functionFlow.exit)
|
||||||
foundExit = true;
|
foundExit = true;
|
||||||
|
|
||||||
if (auto const* functionCall = _node->functionCall)
|
auto const* resolvedFunction = _node->functionDefinition;
|
||||||
|
if (resolvedFunction && resolvedFunction->isImplemented())
|
||||||
{
|
{
|
||||||
auto const* resolvedFunction = ASTNode::resolveFunctionCall(*functionCall, item.contract);
|
CFG::FunctionContractTuple calledFunctionTuple{
|
||||||
|
findScopeContract(*resolvedFunction, item.contract),
|
||||||
if (resolvedFunction && resolvedFunction->isImplemented())
|
resolvedFunction
|
||||||
|
};
|
||||||
|
switch (m_functions.at(calledFunctionTuple))
|
||||||
{
|
{
|
||||||
CFG::FunctionContractTuple calledFunctionTuple{
|
case RevertState::Unknown:
|
||||||
findScopeContract(*resolvedFunction, item.contract),
|
wakeUp[calledFunctionTuple].insert(item);
|
||||||
resolvedFunction
|
foundUnknown = true;
|
||||||
};
|
return;
|
||||||
switch (m_functions.at(calledFunctionTuple))
|
case RevertState::AllPathsRevert:
|
||||||
{
|
return;
|
||||||
case RevertState::Unknown:
|
case RevertState::HasNonRevertingPath:
|
||||||
wakeUp[calledFunctionTuple].insert(item);
|
break;
|
||||||
foundUnknown = true;
|
|
||||||
return;
|
|
||||||
case RevertState::AllPathsRevert:
|
|
||||||
return;
|
|
||||||
case RevertState::HasNonRevertingPath:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,30 +131,26 @@ void ControlFlowRevertPruner::modifyFunctionFlows()
|
|||||||
FunctionFlow const& functionFlow = m_cfg.functionFlow(*item.first.function, item.first.contract);
|
FunctionFlow const& functionFlow = m_cfg.functionFlow(*item.first.function, item.first.contract);
|
||||||
solidity::util::BreadthFirstSearch<CFGNode*>{{functionFlow.entry}}.run(
|
solidity::util::BreadthFirstSearch<CFGNode*>{{functionFlow.entry}}.run(
|
||||||
[&](CFGNode* _node, auto&& _addChild) {
|
[&](CFGNode* _node, auto&& _addChild) {
|
||||||
if (auto const* functionCall = _node->functionCall)
|
auto const* resolvedFunction = _node->functionDefinition;
|
||||||
{
|
if (resolvedFunction && resolvedFunction->isImplemented())
|
||||||
auto const* resolvedFunction = ASTNode::resolveFunctionCall(*functionCall, item.first.contract);
|
switch (m_functions.at({findScopeContract(*resolvedFunction, item.first.contract), resolvedFunction}))
|
||||||
|
{
|
||||||
|
case RevertState::Unknown:
|
||||||
|
[[fallthrough]];
|
||||||
|
case RevertState::AllPathsRevert:
|
||||||
|
// If the revert states of the functions do not
|
||||||
|
// change anymore, we treat all "unknown" states as
|
||||||
|
// "reverting", since they can only be caused by
|
||||||
|
// recursion.
|
||||||
|
for (CFGNode * node: _node->exits)
|
||||||
|
ranges::remove(node->entries, _node);
|
||||||
|
|
||||||
if (resolvedFunction && resolvedFunction->isImplemented())
|
_node->exits = {functionFlow.revert};
|
||||||
switch (m_functions.at({findScopeContract(*resolvedFunction, item.first.contract), resolvedFunction}))
|
functionFlow.revert->entries.push_back(_node);
|
||||||
{
|
return;
|
||||||
case RevertState::Unknown:
|
default:
|
||||||
[[fallthrough]];
|
break;
|
||||||
case RevertState::AllPathsRevert:
|
}
|
||||||
// If the revert states of the functions do not
|
|
||||||
// change anymore, we treat all "unknown" states as
|
|
||||||
// "reverting", since they can only be caused by
|
|
||||||
// recursion.
|
|
||||||
for (CFGNode * node: _node->exits)
|
|
||||||
ranges::remove(node->entries, _node);
|
|
||||||
|
|
||||||
_node->exits = {functionFlow.revert};
|
|
||||||
functionFlow.revert->entries.push_back(_node);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (CFGNode* exit: _node->exits)
|
for (CFGNode* exit: _node->exits)
|
||||||
_addChild(exit);
|
_addChild(exit);
|
||||||
|
Loading…
Reference in New Issue
Block a user