Coverage Report

Created: 2025-09-08 08:10

/src/solidity/libsolidity/analysis/ControlFlowBuilder.cpp
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
#include <libsolidity/analysis/ControlFlowBuilder.h>
20
#include <libsolidity/ast/ASTUtils.h>
21
#include <libyul/AST.h>
22
#include <libyul/Utilities.h>
23
#include <libyul/backends/evm/EVMDialect.h>
24
25
using namespace solidity::langutil;
26
using namespace solidity::frontend;
27
28
ControlFlowBuilder::ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow, ContractDefinition const* _contract):
29
  m_nodeContainer(_nodeContainer),
30
  m_currentNode(_functionFlow.entry),
31
  m_returnNode(_functionFlow.exit),
32
  m_revertNode(_functionFlow.revert),
33
  m_transactionReturnNode(_functionFlow.transactionReturn),
34
  m_contract(_contract)
35
21.2k
{
36
21.2k
}
37
38
39
std::unique_ptr<FunctionFlow> ControlFlowBuilder::createFunctionFlow(
40
  CFG::NodeContainer& _nodeContainer,
41
  FunctionDefinition const& _function,
42
  ContractDefinition const* _contract
43
)
44
21.2k
{
45
21.2k
  auto functionFlow = std::make_unique<FunctionFlow>();
46
21.2k
  functionFlow->entry = _nodeContainer.newNode();
47
21.2k
  functionFlow->exit = _nodeContainer.newNode();
48
21.2k
  functionFlow->revert = _nodeContainer.newNode();
49
21.2k
  functionFlow->transactionReturn = _nodeContainer.newNode();
50
21.2k
  ControlFlowBuilder builder(_nodeContainer, *functionFlow, _contract);
51
21.2k
  builder.appendControlFlow(_function);
52
53
21.2k
  return functionFlow;
54
21.2k
}
55
56
bool ControlFlowBuilder::visit(BinaryOperation const& _operation)
57
68.8k
{
58
68.8k
  solAssert(!!m_currentNode, "");
59
60
68.8k
  switch (_operation.getOperator())
61
68.8k
  {
62
511
    case Token::Or:
63
1.51k
    case Token::And:
64
1.51k
    {
65
1.51k
      visitNode(_operation);
66
1.51k
      solAssert(*_operation.annotation().userDefinedFunction == nullptr);
67
1.51k
      appendControlFlow(_operation.leftExpression());
68
69
1.51k
      auto nodes = splitFlow<2>();
70
1.51k
      nodes[0] = createFlow(nodes[0], _operation.rightExpression());
71
1.51k
      mergeFlow(nodes, nodes[1]);
72
1.51k
      return false;
73
1.51k
    }
74
67.3k
    default:
75
67.3k
    {
76
67.3k
      if (*_operation.annotation().userDefinedFunction != nullptr)
77
49
      {
78
49
        visitNode(_operation);
79
49
        _operation.leftExpression().accept(*this);
80
49
        _operation.rightExpression().accept(*this);
81
82
49
        m_currentNode->functionDefinition = *_operation.annotation().userDefinedFunction;
83
84
49
        auto nextNode = newLabel();
85
86
49
        connect(m_currentNode, nextNode);
87
49
        m_currentNode = nextNode;
88
49
        return false;
89
49
      }
90
67.3k
    }
91
68.8k
  }
92
67.2k
  return ASTConstVisitor::visit(_operation);
93
68.8k
}
94
95
bool ControlFlowBuilder::visit(UnaryOperation const& _operation)
96
20.5k
{
97
20.5k
  solAssert(!!m_currentNode);
98
99
20.5k
  if (*_operation.annotation().userDefinedFunction != nullptr)
100
15
  {
101
15
    visitNode(_operation);
102
15
    _operation.subExpression().accept(*this);
103
15
    m_currentNode->functionDefinition = *_operation.annotation().userDefinedFunction;
104
105
15
    auto nextNode = newLabel();
106
107
15
    connect(m_currentNode, nextNode);
108
15
    m_currentNode = nextNode;
109
15
    return false;
110
15
  }
111
112
20.5k
  return ASTConstVisitor::visit(_operation);
113
20.5k
}
114
115
bool ControlFlowBuilder::visit(Conditional const& _conditional)
116
542
{
117
542
  solAssert(!!m_currentNode, "");
118
542
  visitNode(_conditional);
119
120
542
  _conditional.condition().accept(*this);
121
122
542
  auto nodes = splitFlow<2>();
123
124
542
  nodes[0] = createFlow(nodes[0], _conditional.trueExpression());
125
542
  nodes[1] = createFlow(nodes[1], _conditional.falseExpression());
126
127
542
  mergeFlow(nodes);
128
129
542
  return false;
130
542
}
131
132
bool ControlFlowBuilder::visit(TryStatement const& _tryStatement)
133
135
{
134
135
  appendControlFlow(_tryStatement.externalCall());
135
136
135
  auto nodes = splitFlow(_tryStatement.clauses().size());
137
411
  for (size_t i = 0; i < _tryStatement.clauses().size(); ++i)
138
276
    nodes[i] = createFlow(nodes[i], _tryStatement.clauses()[i]->block());
139
135
  mergeFlow(nodes);
140
141
135
  return false;
142
135
}
143
144
bool ControlFlowBuilder::visit(IfStatement const& _ifStatement)
145
47.1k
{
146
47.1k
  solAssert(!!m_currentNode, "");
147
47.1k
  visitNode(_ifStatement);
148
149
47.1k
  _ifStatement.condition().accept(*this);
150
151
47.1k
  auto nodes = splitFlow<2>();
152
47.1k
  nodes[0] = createFlow(nodes[0], _ifStatement.trueStatement());
153
154
47.1k
  if (_ifStatement.falseStatement())
155
370
  {
156
370
    nodes[1] = createFlow(nodes[1], *_ifStatement.falseStatement());
157
370
    mergeFlow(nodes);
158
370
  }
159
46.8k
  else
160
46.8k
    mergeFlow(nodes, nodes[1]);
161
162
47.1k
  return false;
163
47.1k
}
164
165
bool ControlFlowBuilder::visit(ForStatement const& _forStatement)
166
3.78k
{
167
3.78k
  solAssert(!!m_currentNode, "");
168
3.78k
  visitNode(_forStatement);
169
170
3.78k
  if (_forStatement.initializationExpression())
171
3.72k
    _forStatement.initializationExpression()->accept(*this);
172
173
3.78k
  auto condition = createLabelHere();
174
175
3.78k
  if (_forStatement.condition())
176
3.74k
    appendControlFlow(*_forStatement.condition());
177
178
3.78k
  auto postPart = newLabel();
179
3.78k
  auto nodes = splitFlow<2>();
180
3.78k
  auto afterFor = nodes[1];
181
3.78k
  m_currentNode = nodes[0];
182
183
3.78k
  {
184
3.78k
    BreakContinueScope scope(*this, afterFor, postPart);
185
3.78k
    appendControlFlow(_forStatement.body());
186
3.78k
  }
187
188
3.78k
  placeAndConnectLabel(postPart);
189
190
3.78k
  if (auto expression = _forStatement.loopExpression())
191
3.71k
    appendControlFlow(*expression);
192
193
3.78k
  connect(m_currentNode, condition);
194
3.78k
  m_currentNode = afterFor;
195
196
3.78k
  return false;
197
3.78k
}
198
199
bool ControlFlowBuilder::visit(WhileStatement const& _whileStatement)
200
145
{
201
145
  solAssert(!!m_currentNode, "");
202
145
  visitNode(_whileStatement);
203
204
145
  if (_whileStatement.isDoWhile())
205
31
  {
206
31
    auto afterWhile = newLabel();
207
31
    auto whileBody = createLabelHere();
208
31
    auto condition = newLabel();
209
210
31
    {
211
31
      BreakContinueScope scope(*this, afterWhile, condition);
212
31
      appendControlFlow(_whileStatement.body());
213
31
    }
214
215
31
    placeAndConnectLabel(condition);
216
31
    appendControlFlow(_whileStatement.condition());
217
218
31
    connect(m_currentNode, whileBody);
219
31
    placeAndConnectLabel(afterWhile);
220
31
  }
221
114
  else
222
114
  {
223
114
    auto whileCondition = createLabelHere();
224
225
114
    appendControlFlow(_whileStatement.condition());
226
227
114
    auto nodes = splitFlow<2>();
228
229
114
    auto whileBody = nodes[0];
230
114
    auto afterWhile = nodes[1];
231
232
114
    m_currentNode = whileBody;
233
114
    {
234
114
      BreakContinueScope scope(*this, afterWhile, whileCondition);
235
114
      appendControlFlow(_whileStatement.body());
236
114
    }
237
238
114
    connect(m_currentNode, whileCondition);
239
240
114
    m_currentNode = afterWhile;
241
114
  }
242
243
244
145
  return false;
245
145
}
246
247
bool ControlFlowBuilder::visit(Break const& _break)
248
92
{
249
92
  solAssert(!!m_currentNode, "");
250
92
  solAssert(!!m_breakJump, "");
251
92
  visitNode(_break);
252
92
  connect(m_currentNode, m_breakJump);
253
92
  m_currentNode = newLabel();
254
92
  return false;
255
92
}
256
257
bool ControlFlowBuilder::visit(Continue const& _continue)
258
62
{
259
62
  solAssert(!!m_currentNode, "");
260
62
  solAssert(!!m_continueJump, "");
261
62
  visitNode(_continue);
262
62
  connect(m_currentNode, m_continueJump);
263
62
  m_currentNode = newLabel();
264
62
  return false;
265
62
}
266
267
bool ControlFlowBuilder::visit(Throw const& _throw)
268
0
{
269
0
  solAssert(!!m_currentNode, "");
270
0
  solAssert(!!m_revertNode, "");
271
0
  visitNode(_throw);
272
0
  connect(m_currentNode, m_revertNode);
273
0
  m_currentNode = newLabel();
274
0
  return false;
275
0
}
276
277
bool ControlFlowBuilder::visit(RevertStatement const& _revert)
278
61
{
279
61
  solAssert(!!m_currentNode, "");
280
61
  solAssert(!!m_revertNode, "");
281
61
  visitNode(_revert);
282
61
  connect(m_currentNode, m_revertNode);
283
61
  m_currentNode = newLabel();
284
61
  return false;
285
61
}
286
287
bool ControlFlowBuilder::visit(PlaceholderStatement const&)
288
510
{
289
510
  solAssert(!!m_currentNode, "");
290
510
  solAssert(!!m_placeholderEntry, "");
291
510
  solAssert(!!m_placeholderExit, "");
292
293
510
  connect(m_currentNode, m_placeholderEntry);
294
510
  m_currentNode = newLabel();
295
510
  connect(m_placeholderExit, m_currentNode);
296
510
  return false;
297
510
}
298
299
bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
300
38.6k
{
301
38.6k
  solAssert(!!m_revertNode, "");
302
38.6k
  solAssert(!!m_currentNode, "");
303
38.6k
  solAssert(!!_functionCall.expression().annotation().type, "");
304
305
38.6k
  if (auto functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type))
306
28.1k
    switch (functionType->kind())
307
28.1k
    {
308
131
      case FunctionType::Kind::Revert:
309
131
        visitNode(_functionCall);
310
131
        _functionCall.expression().accept(*this);
311
131
        ASTNode::listAccept(_functionCall.arguments(), *this);
312
313
131
        connect(m_currentNode, m_revertNode);
314
315
131
        m_currentNode = newLabel();
316
131
        return false;
317
420
      case FunctionType::Kind::Require:
318
2.57k
      case FunctionType::Kind::Assert:
319
2.57k
      {
320
2.57k
        visitNode(_functionCall);
321
2.57k
        _functionCall.expression().accept(*this);
322
2.57k
        ASTNode::listAccept(_functionCall.arguments(), *this);
323
324
2.57k
        connect(m_currentNode, m_revertNode);
325
326
2.57k
        auto nextNode = newLabel();
327
328
2.57k
        connect(m_currentNode, nextNode);
329
2.57k
        m_currentNode = nextNode;
330
2.57k
        return false;
331
420
      }
332
11.0k
      case FunctionType::Kind::Internal:
333
11.0k
      {
334
11.0k
        visitNode(_functionCall);
335
11.0k
        _functionCall.expression().accept(*this);
336
11.0k
        ASTNode::listAccept(_functionCall.arguments(), *this);
337
338
11.0k
        m_currentNode->functionDefinition = ASTNode::resolveFunctionCall(_functionCall, m_contract);
339
340
11.0k
        auto nextNode = newLabel();
341
342
11.0k
        connect(m_currentNode, nextNode);
343
11.0k
        m_currentNode = nextNode;
344
345
11.0k
        return false;
346
420
      }
347
14.4k
      default:
348
14.4k
        break;
349
28.1k
    }
350
24.8k
  return ASTConstVisitor::visit(_functionCall);
351
38.6k
}
352
353
bool ControlFlowBuilder::visit(ModifierInvocation const& _modifierInvocation)
354
808
{
355
808
  solAssert(m_contract, "Free functions cannot have modifiers");
356
357
808
  if (auto arguments = _modifierInvocation.arguments())
358
546
    for (auto& argument: *arguments)
359
539
      appendControlFlow(*argument);
360
361
808
  auto modifierDefinition = dynamic_cast<ModifierDefinition const*>(
362
808
    _modifierInvocation.name().annotation().referencedDeclaration
363
808
  );
364
365
808
  if (!modifierDefinition)
366
302
    return false;
367
368
506
  VirtualLookup const& requiredLookup = *_modifierInvocation.name().annotation().requiredLookup;
369
370
506
  if (requiredLookup == VirtualLookup::Virtual)
371
500
    modifierDefinition = &modifierDefinition->resolveVirtual(*m_contract);
372
6
  else
373
506
    solAssert(requiredLookup == VirtualLookup::Static);
374
375
506
  if (!modifierDefinition->isImplemented())
376
23
    return false;
377
378
483
  solAssert(!!m_returnNode, "");
379
380
483
  m_placeholderEntry = newLabel();
381
483
  m_placeholderExit = newLabel();
382
383
483
  appendControlFlow(*modifierDefinition);
384
483
  connect(m_currentNode, m_returnNode);
385
386
483
  m_currentNode = m_placeholderEntry;
387
483
  m_returnNode = m_placeholderExit;
388
389
483
  m_placeholderEntry = nullptr;
390
483
  m_placeholderExit = nullptr;
391
392
483
  return false;
393
483
}
394
395
bool ControlFlowBuilder::visit(FunctionDefinition const& _functionDefinition)
396
21.2k
{
397
21.2k
  for (auto const& parameter: _functionDefinition.parameters())
398
14.2k
    appendControlFlow(*parameter);
399
400
21.2k
  for (auto const& returnParameter: _functionDefinition.returnParameters())
401
13.5k
  {
402
13.5k
    appendControlFlow(*returnParameter);
403
13.5k
    m_returnNode->variableOccurrences.emplace_back(
404
13.5k
      *returnParameter,
405
13.5k
      VariableOccurrence::Kind::Return
406
13.5k
    );
407
408
13.5k
  }
409
410
21.2k
  for (auto const& modifierInvocation: _functionDefinition.modifiers())
411
808
    appendControlFlow(*modifierInvocation);
412
413
21.2k
  appendControlFlow(_functionDefinition.body());
414
415
21.2k
  connect(m_currentNode, m_returnNode);
416
21.2k
  m_currentNode = nullptr;
417
418
21.2k
  return false;
419
21.2k
}
420
421
bool ControlFlowBuilder::visit(Return const& _return)
422
54.5k
{
423
54.5k
  solAssert(!!m_currentNode, "");
424
54.5k
  solAssert(!!m_returnNode, "");
425
54.5k
  visitNode(_return);
426
54.5k
  if (_return.expression())
427
54.2k
  {
428
54.2k
    appendControlFlow(*_return.expression());
429
    // Returns with return expression are considered to be assignments to the return parameters.
430
54.2k
    for (auto returnParameter: _return.annotation().functionReturnParameters->parameters())
431
55.5k
      m_currentNode->variableOccurrences.emplace_back(
432
55.5k
        *returnParameter,
433
55.5k
        VariableOccurrence::Kind::Assignment,
434
55.5k
        _return.location()
435
55.5k
      );
436
54.2k
  }
437
54.5k
  connect(m_currentNode, m_returnNode);
438
54.5k
  m_currentNode = newLabel();
439
54.5k
  return false;
440
54.5k
}
441
442
bool ControlFlowBuilder::visit(FunctionTypeName const& _functionTypeName)
443
495
{
444
495
  visitNode(_functionTypeName);
445
  // Do not visit the parameters and return values of a function type name.
446
  // We do not want to consider them as variable declarations for the control flow graph.
447
495
  return false;
448
495
}
449
450
bool ControlFlowBuilder::visit(InlineAssembly const& _inlineAssembly)
451
2.21k
{
452
2.21k
  solAssert(!!m_currentNode && !m_inlineAssembly, "");
453
454
2.21k
  m_inlineAssembly = &_inlineAssembly;
455
2.21k
  (*this)(_inlineAssembly.operations().root());
456
2.21k
  m_inlineAssembly = nullptr;
457
458
2.21k
  return false;
459
2.21k
}
460
461
void ControlFlowBuilder::visit(yul::Statement const& _statement)
462
4.92k
{
463
4.92k
  solAssert(m_currentNode && m_inlineAssembly, "");
464
4.92k
  solAssert(nativeLocationOf(_statement) == originLocationOf(_statement), "");
465
4.92k
  m_currentNode->location = langutil::SourceLocation::smallestCovering(m_currentNode->location, nativeLocationOf(_statement));
466
4.92k
  ASTWalker::visit(_statement);
467
4.92k
}
468
469
void ControlFlowBuilder::operator()(yul::If const& _if)
470
40
{
471
40
  solAssert(m_currentNode && m_inlineAssembly, "");
472
40
  visit(*_if.condition);
473
474
40
  auto nodes = splitFlow<2>();
475
40
  m_currentNode = nodes[0];
476
40
  (*this)(_if.body);
477
40
  nodes[0] = m_currentNode;
478
40
  mergeFlow(nodes, nodes[1]);
479
40
}
480
481
void ControlFlowBuilder::operator()(yul::Switch const& _switch)
482
35
{
483
35
  solAssert(m_currentNode && m_inlineAssembly, "");
484
35
  visit(*_switch.expression);
485
486
35
  auto beforeSwitch = m_currentNode;
487
488
35
  auto nodes = splitFlow(_switch.cases.size());
489
93
  for (size_t i = 0u; i < _switch.cases.size(); ++i)
490
58
  {
491
58
    m_currentNode = nodes[i];
492
58
    (*this)(_switch.cases[i].body);
493
58
    nodes[i] = m_currentNode;
494
58
  }
495
35
  mergeFlow(nodes);
496
497
35
  if (!hasDefaultCase(_switch))
498
17
    connect(beforeSwitch, m_currentNode);
499
35
}
500
501
void ControlFlowBuilder::operator()(yul::ForLoop const& _forLoop)
502
47
{
503
47
  solAssert(m_currentNode && m_inlineAssembly, "");
504
505
47
  (*this)(_forLoop.pre);
506
507
47
  auto condition = createLabelHere();
508
509
47
  if (_forLoop.condition)
510
47
    visit(*_forLoop.condition);
511
512
47
  auto loopExpression = newLabel();
513
47
  auto nodes = splitFlow<2>();
514
47
  auto afterFor = nodes[1];
515
47
  m_currentNode = nodes[0];
516
517
47
  {
518
47
    BreakContinueScope scope(*this, afterFor, loopExpression);
519
47
    (*this)(_forLoop.body);
520
47
  }
521
522
47
  placeAndConnectLabel(loopExpression);
523
524
47
  (*this)(_forLoop.post);
525
526
47
  connect(m_currentNode, condition);
527
47
  m_currentNode = afterFor;
528
47
}
529
530
void ControlFlowBuilder::operator()(yul::Break const&)
531
16
{
532
16
  solAssert(m_currentNode && m_inlineAssembly, "");
533
16
  solAssert(m_breakJump, "");
534
16
  connect(m_currentNode, m_breakJump);
535
16
  m_currentNode = newLabel();
536
16
}
537
538
void ControlFlowBuilder::operator()(yul::Continue const&)
539
10
{
540
10
  solAssert(m_currentNode && m_inlineAssembly, "");
541
10
  solAssert(m_continueJump, "");
542
10
  connect(m_currentNode, m_continueJump);
543
10
  m_currentNode = newLabel();
544
10
}
545
546
void ControlFlowBuilder::operator()(yul::Identifier const& _identifier)
547
508
{
548
508
  solAssert(m_currentNode && m_inlineAssembly, "");
549
508
  auto const& externalReferences = m_inlineAssembly->annotation().externalReferences;
550
508
  if (externalReferences.count(&_identifier))
551
423
    if (auto const* declaration = dynamic_cast<VariableDeclaration const*>(externalReferences.at(&_identifier).declaration))
552
419
    {
553
419
      solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), "");
554
419
      m_currentNode->variableOccurrences.emplace_back(
555
419
        *declaration,
556
419
        VariableOccurrence::Kind::Access,
557
419
        nativeLocationOf(_identifier)
558
419
      );
559
419
    }
560
508
}
561
562
void ControlFlowBuilder::operator()(yul::Assignment const& _assignment)
563
610
{
564
610
  solAssert(m_currentNode && m_inlineAssembly, "");
565
610
  visit(*_assignment.value);
566
610
  auto const& externalReferences = m_inlineAssembly->annotation().externalReferences;
567
610
  for (auto const& variable: _assignment.variableNames)
568
616
    if (externalReferences.count(&variable))
569
588
      if (auto const* declaration = dynamic_cast<VariableDeclaration const*>(externalReferences.at(&variable).declaration))
570
588
      {
571
588
        solAssert(nativeLocationOf(variable) == originLocationOf(variable), "");
572
588
        m_currentNode->variableOccurrences.emplace_back(
573
588
          *declaration,
574
588
          VariableOccurrence::Kind::Assignment,
575
588
          nativeLocationOf(variable)
576
588
        );
577
588
      }
578
610
}
579
580
void ControlFlowBuilder::operator()(yul::FunctionCall const& _functionCall)
581
6.15k
{
582
6.15k
  using namespace yul;
583
6.15k
  solAssert(m_currentNode && m_inlineAssembly, "");
584
6.15k
  yul::ASTWalker::operator()(_functionCall);
585
586
6.15k
  if (auto const* builtinFunction = resolveBuiltinFunction(_functionCall.functionName, m_inlineAssembly->dialect()))
587
5.99k
  {
588
5.99k
    if (builtinFunction->controlFlowSideEffects.canTerminate)
589
79
      connect(m_currentNode, m_transactionReturnNode);
590
5.99k
    if (builtinFunction->controlFlowSideEffects.canRevert)
591
38
      connect(m_currentNode, m_revertNode);
592
5.99k
    if (!builtinFunction->controlFlowSideEffects.canContinue)
593
117
      m_currentNode = newLabel();
594
5.99k
  }
595
6.15k
}
596
597
void ControlFlowBuilder::operator()(yul::FunctionDefinition const&)
598
197
{
599
197
  solAssert(m_currentNode && m_inlineAssembly, "");
600
  // External references cannot be accessed from within functions, so we can ignore their control flow.
601
  // TODO: we might still want to track if they always revert or return, though.
602
197
}
603
604
void ControlFlowBuilder::operator()(yul::Leave const&)
605
0
{
606
  // This has to be implemented, if we ever decide to visit functions.
607
0
  solUnimplemented("");
608
0
}
609
610
bool ControlFlowBuilder::visit(VariableDeclaration const& _variableDeclaration)
611
39.1k
{
612
39.1k
  solAssert(!!m_currentNode, "");
613
39.1k
  visitNode(_variableDeclaration);
614
615
39.1k
  m_currentNode->variableOccurrences.emplace_back(
616
39.1k
    _variableDeclaration,
617
39.1k
    VariableOccurrence::Kind::Declaration
618
39.1k
  );
619
620
  // Handle declaration with immediate assignment.
621
39.1k
  if (_variableDeclaration.value())
622
0
    m_currentNode->variableOccurrences.emplace_back(
623
0
      _variableDeclaration,
624
0
      VariableOccurrence::Kind::Assignment,
625
0
      _variableDeclaration.value()->location()
626
0
    );
627
  // Function arguments are considered to be immediately assigned as well (they are "externally assigned").
628
39.1k
  else if (_variableDeclaration.isCallableOrCatchParameter() && !_variableDeclaration.isReturnParameter())
629
14.5k
    m_currentNode->variableOccurrences.emplace_back(
630
14.5k
      _variableDeclaration,
631
14.5k
      VariableOccurrence::Kind::Assignment
632
14.5k
    );
633
39.1k
  return true;
634
39.1k
}
635
636
bool ControlFlowBuilder::visit(VariableDeclarationStatement const& _variableDeclarationStatement)
637
10.3k
{
638
10.3k
  solAssert(!!m_currentNode, "");
639
10.3k
  visitNode(_variableDeclarationStatement);
640
641
10.3k
  for (auto const& var: _variableDeclarationStatement.declarations())
642
11.1k
    if (var)
643
11.0k
      var->accept(*this);
644
10.3k
  if (_variableDeclarationStatement.initialValue())
645
8.04k
  {
646
8.04k
    _variableDeclarationStatement.initialValue()->accept(*this);
647
16.8k
    for (size_t i = 0; i < _variableDeclarationStatement.declarations().size(); i++)
648
8.81k
      if (auto const& var = _variableDeclarationStatement.declarations()[i])
649
8.73k
      {
650
8.73k
        auto expression = _variableDeclarationStatement.initialValue();
651
8.73k
        if (auto tupleExpression = dynamic_cast<TupleExpression const*>(expression))
652
118
          if (tupleExpression->components().size() > 1)
653
74
          {
654
74
            solAssert(tupleExpression->components().size() > i, "");
655
74
            expression = tupleExpression->components()[i].get();
656
74
          }
657
8.73k
        expression = resolveOuterUnaryTuples(expression);
658
8.73k
        m_currentNode->variableOccurrences.emplace_back(
659
8.73k
          *var,
660
8.73k
          VariableOccurrence::Kind::Assignment,
661
8.73k
          expression ? std::make_optional(expression->location()) : std::optional<langutil::SourceLocation>{}
662
8.73k
        );
663
8.73k
      }
664
8.04k
  }
665
10.3k
  return false;
666
10.3k
}
667
668
bool ControlFlowBuilder::visit(Identifier const& _identifier)
669
158k
{
670
158k
  solAssert(!!m_currentNode, "");
671
158k
  visitNode(_identifier);
672
673
158k
  if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
674
135k
    m_currentNode->variableOccurrences.emplace_back(
675
135k
      *variableDeclaration,
676
135k
      static_cast<Expression const&>(_identifier).annotation().willBeWrittenTo ?
677
13.0k
      VariableOccurrence::Kind::Assignment :
678
135k
      VariableOccurrence::Kind::Access,
679
135k
      _identifier.location()
680
135k
    );
681
682
158k
  return true;
683
158k
}
684
685
bool ControlFlowBuilder::visitNode(ASTNode const& _node)
686
1.30M
{
687
1.30M
  solAssert(!!m_currentNode, "");
688
1.30M
  m_currentNode->location = langutil::SourceLocation::smallestCovering(m_currentNode->location, _node.location());
689
1.30M
  return true;
690
1.30M
}
691
692
void ControlFlowBuilder::appendControlFlow(ASTNode const& _node)
693
189k
{
694
189k
  _node.accept(*this);
695
189k
}
696
697
CFGNode* ControlFlowBuilder::createFlow(CFGNode* _entry, ASTNode const& _node)
698
50.4k
{
699
50.4k
  auto oldCurrentNode = m_currentNode;
700
50.4k
  m_currentNode = _entry;
701
50.4k
  appendControlFlow(_node);
702
50.4k
  auto endNode = m_currentNode;
703
50.4k
  m_currentNode = oldCurrentNode;
704
50.4k
  return endNode;
705
50.4k
}
706
707
void ControlFlowBuilder::connect(CFGNode* _from, CFGNode* _to)
708
263k
{
709
263k
  solAssert(_from, "");
710
263k
  solAssert(_to, "");
711
263k
  _from->exits.push_back(_to);
712
263k
  _to->entries.push_back(_from);
713
263k
}
714
715
CFGNode* ControlFlowBuilder::newLabel()
716
74.1k
{
717
74.1k
  return m_nodeContainer.newNode();
718
74.1k
}
719
720
CFGNode* ControlFlowBuilder::createLabelHere()
721
3.98k
{
722
3.98k
  auto label = m_nodeContainer.newNode();
723
3.98k
  connect(m_currentNode, label);
724
3.98k
  m_currentNode = label;
725
3.98k
  return label;
726
3.98k
}
727
728
void ControlFlowBuilder::placeAndConnectLabel(CFGNode* _node)
729
3.89k
{
730
3.89k
  connect(m_currentNode, _node);
731
3.89k
  m_currentNode = _node;
732
3.89k
}
733
734
ControlFlowBuilder::BreakContinueScope::BreakContinueScope(
735
  ControlFlowBuilder& _parser,
736
  CFGNode* _breakJump,
737
  CFGNode* _continueJump
738
): m_parser(_parser), m_origBreakJump(_parser.m_breakJump), m_origContinueJump(_parser.m_continueJump)
739
3.98k
{
740
3.98k
  m_parser.m_breakJump = _breakJump;
741
3.98k
  m_parser.m_continueJump = _continueJump;
742
3.98k
}
743
744
ControlFlowBuilder::BreakContinueScope::~BreakContinueScope()
745
3.98k
{
746
3.98k
  m_parser.m_breakJump = m_origBreakJump;
747
3.98k
  m_parser.m_continueJump = m_origContinueJump;
748
3.98k
}