/* 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; }; }; } }