Skip to content

Commit 4b0348a

Browse files
authored
Merge pull request #13693 from ethereum/resolved-function-call-in-cfg
Resolved `FunctionDefinition` instead of `FunctionCall` in CFG
2 parents 4e5a525 + fbe1181 commit 4b0348a

File tree

5 files changed

+47
-51
lines changed

5 files changed

+47
-51
lines changed

libsolidity/analysis/ControlFlowBuilder.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,7 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
300300
_functionCall.expression().accept(*this);
301301
ASTNode::listAccept(_functionCall.arguments(), *this);
302302

303-
solAssert(!m_currentNode->functionCall);
304-
m_currentNode->functionCall = &_functionCall;
303+
m_currentNode->functionDefinition = ASTNode::resolveFunctionCall(_functionCall, m_contract);
305304

306305
auto nextNode = newLabel();
307306

@@ -318,6 +317,8 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
318317

319318
bool ControlFlowBuilder::visit(ModifierInvocation const& _modifierInvocation)
320319
{
320+
solAssert(m_contract, "Free functions cannot have modifiers");
321+
321322
if (auto arguments = _modifierInvocation.arguments())
322323
for (auto& argument: *arguments)
323324
appendControlFlow(*argument);

libsolidity/analysis/ControlFlowBuilder.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ class ControlFlowBuilder: private ASTConstVisitor, private yul::ASTWalker
3838
static std::unique_ptr<FunctionFlow> createFunctionFlow(
3939
CFG::NodeContainer& _nodeContainer,
4040
FunctionDefinition const& _function,
41-
ContractDefinition const* _contract = nullptr
41+
ContractDefinition const* _contract
4242
);
4343

4444
private:
4545
explicit ControlFlowBuilder(
4646
CFG::NodeContainer& _nodeContainer,
4747
FunctionFlow const& _functionFlow,
48-
ContractDefinition const* _contract = nullptr
48+
ContractDefinition const* _contract
4949
);
5050

5151
// Visits for constructing the control flow.

libsolidity/analysis/ControlFlowGraph.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ bool CFG::constructFlow(ASTNode const& _astRoot)
3434
bool CFG::visit(FunctionDefinition const& _function)
3535
{
3636
if (_function.isImplemented() && _function.isFree())
37-
m_functionControlFlow[{nullptr, &_function}] = ControlFlowBuilder::createFunctionFlow(m_nodeContainer, _function);
37+
m_functionControlFlow[{nullptr, &_function}] = ControlFlowBuilder::createFunctionFlow(
38+
m_nodeContainer,
39+
_function,
40+
nullptr /* _contract */
41+
);
3842
return false;
3943
}
4044

libsolidity/analysis/ControlFlowGraph.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,8 @@ struct CFGNode
9898
std::vector<CFGNode*> entries;
9999
/// Exit nodes. All CFG nodes to which control flow may continue after this node.
100100
std::vector<CFGNode*> exits;
101-
/// Function call done by this node
102-
FunctionCall const* functionCall = nullptr;
103-
101+
/// Resolved definition of the function called by this node
102+
FunctionDefinition const* functionDefinition = nullptr;
104103
/// Variable occurrences in the node.
105104
std::vector<VariableOccurrence> variableOccurrences;
106105
// Source location of this control flow block.

libsolidity/analysis/ControlFlowRevertPruner.cpp

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -81,27 +81,23 @@ void ControlFlowRevertPruner::findRevertStates()
8181
if (_node == functionFlow.exit)
8282
foundExit = true;
8383

84-
if (auto const* functionCall = _node->functionCall)
84+
auto const* resolvedFunction = _node->functionDefinition;
85+
if (resolvedFunction && resolvedFunction->isImplemented())
8586
{
86-
auto const* resolvedFunction = ASTNode::resolveFunctionCall(*functionCall, item.contract);
87-
88-
if (resolvedFunction && resolvedFunction->isImplemented())
87+
CFG::FunctionContractTuple calledFunctionTuple{
88+
findScopeContract(*resolvedFunction, item.contract),
89+
resolvedFunction
90+
};
91+
switch (m_functions.at(calledFunctionTuple))
8992
{
90-
CFG::FunctionContractTuple calledFunctionTuple{
91-
findScopeContract(*resolvedFunction, item.contract),
92-
resolvedFunction
93-
};
94-
switch (m_functions.at(calledFunctionTuple))
95-
{
96-
case RevertState::Unknown:
97-
wakeUp[calledFunctionTuple].insert(item);
98-
foundUnknown = true;
99-
return;
100-
case RevertState::AllPathsRevert:
101-
return;
102-
case RevertState::HasNonRevertingPath:
103-
break;
104-
}
93+
case RevertState::Unknown:
94+
wakeUp[calledFunctionTuple].insert(item);
95+
foundUnknown = true;
96+
return;
97+
case RevertState::AllPathsRevert:
98+
return;
99+
case RevertState::HasNonRevertingPath:
100+
break;
105101
}
106102
}
107103

@@ -135,30 +131,26 @@ void ControlFlowRevertPruner::modifyFunctionFlows()
135131
FunctionFlow const& functionFlow = m_cfg.functionFlow(*item.first.function, item.first.contract);
136132
solidity::util::BreadthFirstSearch<CFGNode*>{{functionFlow.entry}}.run(
137133
[&](CFGNode* _node, auto&& _addChild) {
138-
if (auto const* functionCall = _node->functionCall)
139-
{
140-
auto const* resolvedFunction = ASTNode::resolveFunctionCall(*functionCall, item.first.contract);
141-
142-
if (resolvedFunction && resolvedFunction->isImplemented())
143-
switch (m_functions.at({findScopeContract(*resolvedFunction, item.first.contract), resolvedFunction}))
144-
{
145-
case RevertState::Unknown:
146-
[[fallthrough]];
147-
case RevertState::AllPathsRevert:
148-
// If the revert states of the functions do not
149-
// change anymore, we treat all "unknown" states as
150-
// "reverting", since they can only be caused by
151-
// recursion.
152-
for (CFGNode * node: _node->exits)
153-
ranges::remove(node->entries, _node);
154-
155-
_node->exits = {functionFlow.revert};
156-
functionFlow.revert->entries.push_back(_node);
157-
return;
158-
default:
159-
break;
160-
}
161-
}
134+
auto const* resolvedFunction = _node->functionDefinition;
135+
if (resolvedFunction && resolvedFunction->isImplemented())
136+
switch (m_functions.at({findScopeContract(*resolvedFunction, item.first.contract), resolvedFunction}))
137+
{
138+
case RevertState::Unknown:
139+
[[fallthrough]];
140+
case RevertState::AllPathsRevert:
141+
// If the revert states of the functions do not
142+
// change anymore, we treat all "unknown" states as
143+
// "reverting", since they can only be caused by
144+
// recursion.
145+
for (CFGNode * node: _node->exits)
146+
ranges::remove(node->entries, _node);
147+
148+
_node->exits = {functionFlow.revert};
149+
functionFlow.revert->entries.push_back(_node);
150+
return;
151+
default:
152+
break;
153+
}
162154

163155
for (CFGNode* exit: _node->exits)
164156
_addChild(exit);

0 commit comments

Comments
 (0)