Coverage Report

Created: 2025-09-08 08:10

/src/solidity/libsolidity/analysis/ControlFlowBuilder.h
Line
Count
Source
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
42
  );
43
44
private:
45
  explicit ControlFlowBuilder(
46
    CFG::NodeContainer& _nodeContainer,
47
    FunctionFlow const& _functionFlow,
48
    ContractDefinition const* _contract
49
  );
50
51
  // Visits for constructing the control flow.
52
  bool visit(BinaryOperation const& _operation) override;
53
  bool visit(UnaryOperation const& _operation) override;
54
  bool visit(Conditional const& _conditional) override;
55
  bool visit(TryStatement const& _tryStatement) override;
56
  bool visit(IfStatement const& _ifStatement) override;
57
  bool visit(ForStatement const& _forStatement) override;
58
  bool visit(WhileStatement const& _whileStatement) override;
59
  bool visit(Break const&) override;
60
  bool visit(Continue const&) override;
61
  bool visit(Throw const&) override;
62
  bool visit(RevertStatement const&) override;
63
  bool visit(PlaceholderStatement const&) override;
64
  bool visit(FunctionCall const& _functionCall) override;
65
  bool visit(ModifierInvocation const& _modifierInvocation) override;
66
67
  // Visits for constructing the control flow as well as filling variable occurrences.
68
  bool visit(FunctionDefinition const& _functionDefinition) override;
69
  bool visit(Return const& _return) override;
70
71
  // Visits for filling variable occurrences.
72
  bool visit(FunctionTypeName const& _functionTypeName) override;
73
  bool visit(InlineAssembly const& _inlineAssembly) override;
74
  void visit(yul::Statement const& _statement) override;
75
  void operator()(yul::If const& _if) override;
76
  void operator()(yul::Switch const& _switch) override;
77
  void operator()(yul::ForLoop const& _for) override;
78
  void operator()(yul::Break const&) override;
79
  void operator()(yul::Continue const&) override;
80
  void operator()(yul::Identifier const& _identifier) override;
81
  void operator()(yul::Assignment const& _assignment) override;
82
  void operator()(yul::FunctionCall const& _functionCall) override;
83
  void operator()(yul::FunctionDefinition const& _functionDefinition) override;
84
  void operator()(yul::Leave const& _leaveStatement) override;
85
  bool visit(VariableDeclaration const& _variableDeclaration) override;
86
  bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override;
87
  bool visit(Identifier const& _identifier) override;
88
89
protected:
90
  bool visitNode(ASTNode const&) override;
91
92
private:
93
  using ASTConstVisitor::visit;
94
  using yul::ASTWalker::visit;
95
  using yul::ASTWalker::operator();
96
97
  /// Appends the control flow of @a _node to the current control flow.
98
  void appendControlFlow(ASTNode const& _node);
99
100
  /// Starts at @a _entry and parses the control flow of @a _node.
101
  /// @returns The node at which the parsed control flow ends.
102
  /// m_currentNode is not affected (it is saved and restored).
103
  CFGNode* createFlow(CFGNode* _entry, ASTNode const& _node);
104
105
  /// Creates an arc from @a _from to @a _to.
106
  static void connect(CFGNode* _from, CFGNode* _to);
107
108
  /// Splits the control flow starting at the current node into n paths.
109
  /// m_currentNode is set to nullptr and has to be set manually or
110
  /// using mergeFlow later.
111
  template<size_t n>
112
  std::array<CFGNode*, n> splitFlow()
113
53.2k
  {
114
53.2k
    std::array<CFGNode*, n> result;
115
53.2k
    for (auto& node: result)
116
106k
    {
117
106k
      node = m_nodeContainer.newNode();
118
106k
      connect(m_currentNode, node);
119
106k
    }
120
53.2k
    m_currentNode = nullptr;
121
53.2k
    return result;
122
53.2k
  }
123
124
  /// Splits the control flow starting at the current node into @a _n paths.
125
  /// m_currentNode is set to nullptr and has to be set manually or
126
  /// using mergeFlow later.
127
  std::vector<CFGNode*> splitFlow(size_t n)
128
170
  {
129
170
    std::vector<CFGNode*> result(n);
130
170
    for (auto& node: result)
131
334
    {
132
334
      node = m_nodeContainer.newNode();
133
334
      connect(m_currentNode, node);
134
334
    }
135
170
    m_currentNode = nullptr;
136
170
    return result;
137
170
  }
138
139
  /// Merges the control flow of @a _nodes to @a _endNode.
140
  /// If @a _endNode is nullptr, a new node is created and used as end node.
141
  /// Sets the merge destination as current node.
142
  /// Note: @a _endNode may be one of the nodes in @a _nodes.
143
  template<typename C>
144
  void mergeFlow(C const& _nodes, CFGNode* _endNode = nullptr)
145
49.4k
  {
146
49.4k
    CFGNode* mergeDestination = (_endNode == nullptr) ? m_nodeContainer.newNode() : _endNode;
147
49.4k
    for (auto& node: _nodes)
148
98.9k
      if (node != mergeDestination)
149
50.5k
        connect(node, mergeDestination);
150
49.4k
    m_currentNode = mergeDestination;
151
49.4k
  }
void solidity::frontend::ControlFlowBuilder::mergeFlow<std::__1::array<solidity::frontend::CFGNode*, 2ul> >(std::__1::array<solidity::frontend::CFGNode*, 2ul> const&, solidity::frontend::CFGNode*)
Line
Count
Source
145
49.2k
  {
146
49.2k
    CFGNode* mergeDestination = (_endNode == nullptr) ? m_nodeContainer.newNode() : _endNode;
147
49.2k
    for (auto& node: _nodes)
148
98.5k
      if (node != mergeDestination)
149
50.1k
        connect(node, mergeDestination);
150
49.2k
    m_currentNode = mergeDestination;
151
49.2k
  }
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*)
Line
Count
Source
145
170
  {
146
170
    CFGNode* mergeDestination = (_endNode == nullptr) ? m_nodeContainer.newNode() : _endNode;
147
170
    for (auto& node: _nodes)
148
334
      if (node != mergeDestination)
149
334
        connect(node, mergeDestination);
150
170
    m_currentNode = mergeDestination;
151
170
  }
152
153
  CFGNode* newLabel();
154
  CFGNode* createLabelHere();
155
  void placeAndConnectLabel(CFGNode *_node);
156
157
  CFG::NodeContainer& m_nodeContainer;
158
159
  CFGNode* m_currentNode = nullptr;
160
  CFGNode* m_returnNode = nullptr;
161
  CFGNode* m_revertNode = nullptr;
162
  CFGNode* m_transactionReturnNode = nullptr;
163
164
  ContractDefinition const* m_contract = nullptr;
165
166
  /// The current jump destination of break Statements.
167
  CFGNode* m_breakJump = nullptr;
168
  /// The current jump destination of continue Statements.
169
  CFGNode* m_continueJump = nullptr;
170
171
  CFGNode* m_placeholderEntry = nullptr;
172
  CFGNode* m_placeholderExit = nullptr;
173
174
  InlineAssembly const* m_inlineAssembly = nullptr;
175
176
  /// Helper class that replaces the break and continue jump destinations for the
177
  /// current scope and restores the originals at the end of the scope.
178
  class BreakContinueScope
179
  {
180
  public:
181
    BreakContinueScope(ControlFlowBuilder& _parser, CFGNode* _breakJump, CFGNode* _continueJump);
182
    ~BreakContinueScope();
183
  private:
184
    ControlFlowBuilder& m_parser;
185
    CFGNode* m_origBreakJump;
186
    CFGNode* m_origContinueJump;
187
  };
188
};
189
190
}