Coverage Report

Created: 2022-08-24 06:55

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