/src/solidity/libsolidity/analysis/ControlFlowBuilder.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | |
19 | | #pragma once |
20 | | |
21 | | #include <libsolidity/analysis/ControlFlowGraph.h> |
22 | | #include <libsolidity/ast/AST.h> |
23 | | #include <libsolidity/ast/ASTVisitor.h> |
24 | | #include <libyul/optimiser/ASTWalker.h> |
25 | | |
26 | | #include <array> |
27 | | #include <memory> |
28 | | |
29 | | namespace solidity::frontend |
30 | | { |
31 | | |
32 | | /** |
33 | | * Helper class that builds the control flow of a function or modifier. |
34 | | */ |
35 | | class ControlFlowBuilder: private ASTConstVisitor, private yul::ASTWalker |
36 | | { |
37 | | public: |
38 | | static std::unique_ptr<FunctionFlow> createFunctionFlow( |
39 | | CFG::NodeContainer& _nodeContainer, |
40 | | FunctionDefinition const& _function, |
41 | | ContractDefinition const* _contract = nullptr |
42 | | ); |
43 | | |
44 | | private: |
45 | | explicit ControlFlowBuilder( |
46 | | CFG::NodeContainer& _nodeContainer, |
47 | | FunctionFlow const& _functionFlow, |
48 | | ContractDefinition const* _contract = nullptr |
49 | | ); |
50 | | |
51 | | // Visits for constructing the control flow. |
52 | | bool visit(BinaryOperation const& _operation) override; |
53 | | bool visit(Conditional const& _conditional) override; |
54 | | bool visit(TryStatement const& _tryStatement) override; |
55 | | bool visit(IfStatement const& _ifStatement) override; |
56 | | bool visit(ForStatement const& _forStatement) override; |
57 | | bool visit(WhileStatement const& _whileStatement) override; |
58 | | bool visit(Break const&) override; |
59 | | bool visit(Continue const&) override; |
60 | | bool visit(Throw const&) override; |
61 | | bool visit(RevertStatement const&) override; |
62 | | bool visit(PlaceholderStatement const&) override; |
63 | | bool visit(FunctionCall const& _functionCall) override; |
64 | | bool visit(ModifierInvocation const& _modifierInvocation) override; |
65 | | |
66 | | // Visits for constructing the control flow as well as filling variable occurrences. |
67 | | bool visit(FunctionDefinition const& _functionDefinition) override; |
68 | | bool visit(Return const& _return) override; |
69 | | |
70 | | // Visits for filling variable occurrences. |
71 | | bool visit(FunctionTypeName const& _functionTypeName) override; |
72 | | bool visit(InlineAssembly const& _inlineAssembly) override; |
73 | | void visit(yul::Statement const& _statement) override; |
74 | | void operator()(yul::If const& _if) override; |
75 | | void operator()(yul::Switch const& _switch) override; |
76 | | void operator()(yul::ForLoop const& _for) override; |
77 | | void operator()(yul::Break const&) override; |
78 | | void operator()(yul::Continue const&) override; |
79 | | void operator()(yul::Identifier const& _identifier) override; |
80 | | void operator()(yul::Assignment const& _assignment) override; |
81 | | void operator()(yul::FunctionCall const& _functionCall) override; |
82 | | void operator()(yul::FunctionDefinition const& _functionDefinition) override; |
83 | | void operator()(yul::Leave const& _leaveStatement) override; |
84 | | bool visit(VariableDeclaration const& _variableDeclaration) override; |
85 | | bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; |
86 | | bool visit(Identifier const& _identifier) override; |
87 | | |
88 | | protected: |
89 | | bool visitNode(ASTNode const&) override; |
90 | | |
91 | | private: |
92 | | using ASTConstVisitor::visit; |
93 | | using yul::ASTWalker::visit; |
94 | | using yul::ASTWalker::operator(); |
95 | | |
96 | | /// Appends the control flow of @a _node to the current control flow. |
97 | | void appendControlFlow(ASTNode const& _node); |
98 | | |
99 | | /// Starts at @a _entry and parses the control flow of @a _node. |
100 | | /// @returns The node at which the parsed control flow ends. |
101 | | /// m_currentNode is not affected (it is saved and restored). |
102 | | CFGNode* createFlow(CFGNode* _entry, ASTNode const& _node); |
103 | | |
104 | | /// Creates an arc from @a _from to @a _to. |
105 | | static void connect(CFGNode* _from, CFGNode* _to); |
106 | | |
107 | | /// Splits the control flow starting at the current node into n paths. |
108 | | /// m_currentNode is set to nullptr and has to be set manually or |
109 | | /// using mergeFlow later. |
110 | | template<size_t n> |
111 | | std::array<CFGNode*, n> splitFlow() |
112 | 0 | { |
113 | 0 | std::array<CFGNode*, n> result; |
114 | 0 | for (auto& node: result) |
115 | 0 | { |
116 | 0 | node = m_nodeContainer.newNode(); |
117 | 0 | connect(m_currentNode, node); |
118 | 0 | } |
119 | 0 | m_currentNode = nullptr; |
120 | 0 | return result; |
121 | 0 | } |
122 | | |
123 | | /// Splits the control flow starting at the current node into @a _n paths. |
124 | | /// m_currentNode is set to nullptr and has to be set manually or |
125 | | /// using mergeFlow later. |
126 | | std::vector<CFGNode*> splitFlow(size_t n) |
127 | 0 | { |
128 | 0 | std::vector<CFGNode*> result(n); |
129 | 0 | for (auto& node: result) |
130 | 0 | { |
131 | 0 | node = m_nodeContainer.newNode(); |
132 | 0 | connect(m_currentNode, node); |
133 | 0 | } |
134 | 0 | m_currentNode = nullptr; |
135 | 0 | return result; |
136 | 0 | } |
137 | | |
138 | | /// Merges the control flow of @a _nodes to @a _endNode. |
139 | | /// If @a _endNode is nullptr, a new node is creates and used as end node. |
140 | | /// Sets the merge destination as current node. |
141 | | /// Note: @a _endNode may be one of the nodes in @a _nodes. |
142 | | template<typename C> |
143 | | void mergeFlow(C const& _nodes, CFGNode* _endNode = nullptr) |
144 | 0 | { |
145 | 0 | CFGNode* mergeDestination = (_endNode == nullptr) ? m_nodeContainer.newNode() : _endNode; |
146 | 0 | for (auto& node: _nodes) |
147 | 0 | if (node != mergeDestination) |
148 | 0 | connect(node, mergeDestination); |
149 | 0 | m_currentNode = mergeDestination; |
150 | 0 | } Unexecuted instantiation: void solidity::frontend::ControlFlowBuilder::mergeFlow<std::__1::array<solidity::frontend::CFGNode*, 2ul> >(std::__1::array<solidity::frontend::CFGNode*, 2ul> const&, solidity::frontend::CFGNode*) Unexecuted instantiation: void solidity::frontend::ControlFlowBuilder::mergeFlow<std::__1::vector<solidity::frontend::CFGNode*, std::__1::allocator<solidity::frontend::CFGNode*> > >(std::__1::vector<solidity::frontend::CFGNode*, std::__1::allocator<solidity::frontend::CFGNode*> > const&, solidity::frontend::CFGNode*) |
151 | | |
152 | | CFGNode* newLabel(); |
153 | | CFGNode* createLabelHere(); |
154 | | void placeAndConnectLabel(CFGNode *_node); |
155 | | |
156 | | CFG::NodeContainer& m_nodeContainer; |
157 | | |
158 | | CFGNode* m_currentNode = nullptr; |
159 | | CFGNode* m_returnNode = nullptr; |
160 | | CFGNode* m_revertNode = nullptr; |
161 | | CFGNode* m_transactionReturnNode = nullptr; |
162 | | |
163 | | ContractDefinition const* m_contract = nullptr; |
164 | | |
165 | | /// The current jump destination of break Statements. |
166 | | CFGNode* m_breakJump = nullptr; |
167 | | /// The current jump destination of continue Statements. |
168 | | CFGNode* m_continueJump = nullptr; |
169 | | |
170 | | CFGNode* m_placeholderEntry = nullptr; |
171 | | CFGNode* m_placeholderExit = nullptr; |
172 | | |
173 | | InlineAssembly const* m_inlineAssembly = nullptr; |
174 | | |
175 | | /// Helper class that replaces the break and continue jump destinations for the |
176 | | /// current scope and restores the originals at the end of the scope. |
177 | | class BreakContinueScope |
178 | | { |
179 | | public: |
180 | | BreakContinueScope(ControlFlowBuilder& _parser, CFGNode* _breakJump, CFGNode* _continueJump); |
181 | | ~BreakContinueScope(); |
182 | | private: |
183 | | ControlFlowBuilder& m_parser; |
184 | | CFGNode* m_origBreakJump; |
185 | | CFGNode* m_origContinueJump; |
186 | | }; |
187 | | }; |
188 | | |
189 | | } |