/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see .
*/
#pragma once
#include
#include
#include
#include
#include
namespace dev {
namespace solidity {
/** Helper class that builds the control flow of a function or modifier.
* Modifiers are not yet applied to the functions. This is done in a second
* step in the CFG class.
*/
class ControlFlowBuilder: private ASTConstVisitor
{
public:
static std::unique_ptr createFunctionFlow(
CFG::NodeContainer& _nodeContainer,
FunctionDefinition const& _function
);
static std::unique_ptr createModifierFlow(
CFG::NodeContainer& _nodeContainer,
ModifierDefinition const& _modifier
);
private:
explicit ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow);
virtual bool visit(BinaryOperation const& _operation) override;
virtual bool visit(Conditional const& _conditional) override;
virtual bool visit(IfStatement const& _ifStatement) override;
virtual bool visit(ForStatement const& _forStatement) override;
virtual bool visit(WhileStatement const& _whileStatement) override;
virtual bool visit(Break const&) override;
virtual bool visit(Continue const&) override;
virtual bool visit(Throw const&) override;
virtual bool visit(Block const&) override;
virtual void endVisit(Block const&) override;
virtual bool visit(Return const& _return) override;
virtual bool visit(PlaceholderStatement const&) override;
virtual bool visit(FunctionCall const& _functionCall) override;
/// Appends the control flow of @a _node to the current control flow.
void appendControlFlow(ASTNode const& _node);
/// Starts at @a _entry and parses the control flow of @a _node.
/// @returns The node at which the parsed control flow ends.
/// m_currentNode is not affected (it is saved and restored).
CFGNode* createFlow(CFGNode* _entry, ASTNode const& _node);
/// Creates an arc from @a _from to @a _to.
static void connect(CFGNode* _from, CFGNode* _to);
protected:
virtual bool visitNode(ASTNode const& node) override;
private:
/// Splits the control flow starting at the current node into n paths.
/// m_currentNode is set to nullptr and has to be set manually or
/// using mergeFlow later.
template
std::array splitFlow()
{
std::array result;
for (auto& node: result)
{
node = m_nodeContainer.newNode();
connect(m_currentNode, node);
}
m_currentNode = nullptr;
return result;
}
/// Merges the control flow of @a _nodes to @a _endNode.
/// If @a _endNode is nullptr, a new node is creates and used as end node.
/// Sets the merge destination as current node.
/// Note: @a _endNode may be one of the nodes in @a _nodes.
template
void mergeFlow(std::array const& _nodes, CFGNode* _endNode = nullptr)
{
CFGNode* mergeDestination = (_endNode == nullptr) ? m_nodeContainer.newNode() : _endNode;
for (auto& node: _nodes)
if (node != mergeDestination)
connect(node, mergeDestination);
m_currentNode = mergeDestination;
}
CFGNode* newLabel();
CFGNode* createLabelHere();
void placeAndConnectLabel(CFGNode *_node);
CFG::NodeContainer& m_nodeContainer;
/// The control flow of the function that is currently parsed.
/// Note: this can also be a ModifierFlow
FunctionFlow const& m_currentFunctionFlow;
CFGNode* m_currentNode = nullptr;
/// The current jump destination of break Statements.
CFGNode* m_breakJump = nullptr;
/// The current jump destination of continue Statements.
CFGNode* m_continueJump = nullptr;
/// Helper class that replaces the break and continue jump destinations for the
/// current scope and restores the originals at the end of the scope.
class BreakContinueScope
{
public:
BreakContinueScope(ControlFlowBuilder& _parser, CFGNode* _breakJump, CFGNode* _continueJump);
~BreakContinueScope();
private:
ControlFlowBuilder& m_parser;
CFGNode* m_origBreakJump;
CFGNode* m_origContinueJump;
};
};
}
}