Coverage Report

Created: 2022-08-24 06:43

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