Coverage Report

Created: 2022-05-14 11:35

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- Transfer.cpp --------------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file defines transfer functions that evaluate program statements and
10
//  update an environment accordingly.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/Analysis/FlowSensitive/Transfer.h"
15
#include "clang/AST/Decl.h"
16
#include "clang/AST/DeclBase.h"
17
#include "clang/AST/DeclCXX.h"
18
#include "clang/AST/Expr.h"
19
#include "clang/AST/ExprCXX.h"
20
#include "clang/AST/OperationKinds.h"
21
#include "clang/AST/Stmt.h"
22
#include "clang/AST/StmtVisitor.h"
23
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
24
#include "clang/Analysis/FlowSensitive/Value.h"
25
#include "clang/Basic/Builtins.h"
26
#include "clang/Basic/OperatorKinds.h"
27
#include "llvm/ADT/STLExtras.h"
28
#include "llvm/Support/Casting.h"
29
#include <cassert>
30
#include <memory>
31
#include <tuple>
32
33
namespace clang {
34
namespace dataflow {
35
36
static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
37
22
                                          Environment &Env) {
38
22
  if (auto *LHSValue =
39
22
          dyn_cast_or_null<BoolValue>(Env.getValue(LHS, SkipPast::Reference)))
40
4
    if (auto *RHSValue =
41
4
            dyn_cast_or_null<BoolValue>(Env.getValue(RHS, SkipPast::Reference)))
42
4
      return Env.makeIff(*LHSValue, *RHSValue);
43
44
18
  return Env.makeAtomicBoolValue();
45
22
}
46
47
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
48
public:
49
  TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
50
5.80k
      : StmtToEnv(StmtToEnv), Env(Env) {}
51
52
136
  void VisitBinaryOperator(const BinaryOperator *S) {
53
136
    const Expr *LHS = S->getLHS();
54
136
    assert(LHS != nullptr);
55
56
0
    const Expr *RHS = S->getRHS();
57
136
    assert(RHS != nullptr);
58
59
0
    switch (S->getOpcode()) {
60
82
    case BO_Assign: {
61
82
      auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
62
82
      if (LHSLoc == nullptr)
63
2
        break;
64
65
80
      auto *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
66
80
      if (RHSVal == nullptr)
67
52
        break;
68
69
      // Assign a value to the storage location of the left-hand side.
70
28
      Env.setValue(*LHSLoc, *RHSVal);
71
72
      // Assign a storage location for the whole expression.
73
28
      Env.setStorageLocation(*S, *LHSLoc);
74
28
      break;
75
80
    }
76
14
    case BO_LAnd:
77
24
    case BO_LOr: {
78
24
      BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
79
24
      BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
80
81
24
      auto &Loc = Env.createStorageLocation(*S);
82
24
      Env.setStorageLocation(*S, Loc);
83
24
      if (S->getOpcode() == BO_LAnd)
84
14
        Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
85
10
      else
86
10
        Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
87
24
      break;
88
14
    }
89
20
    case BO_NE:
90
22
    case BO_EQ: {
91
22
      auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
92
22
      auto &Loc = Env.createStorageLocation(*S);
93
22
      Env.setStorageLocation(*S, Loc);
94
22
      Env.setValue(Loc, S->getOpcode() == BO_EQ ? 
LHSEqRHSValue2
95
22
                                                : 
Env.makeNot(LHSEqRHSValue)20
);
96
22
      break;
97
20
    }
98
8
    default:
99
8
      break;
100
136
    }
101
136
  }
102
103
1.32k
  void VisitDeclRefExpr(const DeclRefExpr *S) {
104
1.32k
    assert(S->getDecl() != nullptr);
105
0
    auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
106
1.32k
    if (DeclLoc == nullptr)
107
298
      return;
108
109
1.02k
    if (S->getDecl()->getType()->isReferenceType()) {
110
31
      Env.setStorageLocation(*S, *DeclLoc);
111
993
    } else {
112
993
      auto &Loc = Env.createStorageLocation(*S);
113
993
      auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
114
993
      Env.setStorageLocation(*S, Loc);
115
993
      Env.setValue(Loc, Val);
116
993
    }
117
1.02k
  }
118
119
583
  void VisitDeclStmt(const DeclStmt *S) {
120
    // Group decls are converted into single decls in the CFG so the cast below
121
    // is safe.
122
583
    const auto &D = *cast<VarDecl>(S->getSingleDecl());
123
124
    // Static local vars are already initialized in `Environment`.
125
583
    if (D.hasGlobalStorage())
126
6
      return;
127
128
577
    auto &Loc = Env.createStorageLocation(D);
129
577
    Env.setStorageLocation(D, Loc);
130
131
577
    const Expr *InitExpr = D.getInit();
132
577
    if (InitExpr == nullptr) {
133
      // No initializer expression - associate `Loc` with a new value.
134
64
      if (Value *Val = Env.createValue(D.getType()))
135
64
        Env.setValue(Loc, *Val);
136
64
      return;
137
64
    }
138
139
513
    InitExpr = D.getInit();
140
513
    assert(InitExpr != nullptr);
141
142
513
    if (D.getType()->isReferenceType()) {
143
      // Initializing a reference variable - do not create a reference to
144
      // reference.
145
15
      if (auto *InitExprLoc =
146
15
              Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
147
8
        auto &Val =
148
8
            Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
149
8
        Env.setValue(Loc, Val);
150
8
        return;
151
8
      }
152
498
    } else if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
153
447
      Env.setValue(Loc, *InitExprVal);
154
447
      return;
155
447
    }
156
157
    // We arrive here in (the few) cases where an expression is intentionally
158
    // "uninterpreted". There are two ways to handle this situation: propagate
159
    // the status, so that uninterpreted initializers result in uninterpreted
160
    // variables, or provide a default value. We choose the latter so that later
161
    // refinements of the variable can be used for reasoning about the
162
    // surrounding code.
163
    //
164
    // FIXME. If and when we interpret all language cases, change this to assert
165
    // that `InitExpr` is interpreted, rather than supplying a default value
166
    // (assuming we don't update the environment API to return references).
167
58
    if (Value *Val = Env.createValue(D.getType()))
168
56
      Env.setValue(Loc, *Val);
169
58
  }
170
171
854
  void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
172
854
    const Expr *SubExpr = S->getSubExpr();
173
854
    assert(SubExpr != nullptr);
174
175
0
    switch (S->getCastKind()) {
176
6
    case CK_IntegralToBoolean: {
177
      // This cast creates a new, boolean value from the integral value. We
178
      // model that with a fresh value in the environment, unless it's already a
179
      // boolean.
180
6
      auto &Loc = Env.createStorageLocation(*S);
181
6
      Env.setStorageLocation(*S, Loc);
182
6
      if (auto *SubExprVal = dyn_cast_or_null<BoolValue>(
183
6
              Env.getValue(*SubExpr, SkipPast::Reference)))
184
4
        Env.setValue(Loc, *SubExprVal);
185
2
      else
186
        // FIXME: If integer modeling is added, then update this code to create
187
        // the boolean based on the integer model.
188
2
        Env.setValue(Loc, Env.makeAtomicBoolValue());
189
6
      break;
190
0
    }
191
192
280
    case CK_LValueToRValue: {
193
280
      auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
194
280
      if (SubExprVal == nullptr)
195
5
        break;
196
197
275
      auto &ExprLoc = Env.createStorageLocation(*S);
198
275
      Env.setStorageLocation(*S, ExprLoc);
199
275
      Env.setValue(ExprLoc, *SubExprVal);
200
275
      break;
201
280
    }
202
203
18
    case CK_IntegralCast:
204
      // FIXME: This cast creates a new integral value from the
205
      // subexpression. But, because we don't model integers, we don't
206
      // distinguish between this new value and the underlying one. If integer
207
      // modeling is added, then update this code to create a fresh location and
208
      // value.
209
28
    case CK_UncheckedDerivedToBase:
210
112
    case CK_ConstructorConversion:
211
118
    case CK_UserDefinedConversion:
212
      // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
213
      // CK_ConstructorConversion, and CK_UserDefinedConversion.
214
226
    case CK_NoOp: {
215
      // FIXME: Consider making `Environment::getStorageLocation` skip noop
216
      // expressions (this and other similar expressions in the file) instead of
217
      // assigning them storage locations.
218
226
      auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
219
226
      if (SubExprLoc == nullptr)
220
6
        break;
221
222
220
      Env.setStorageLocation(*S, *SubExprLoc);
223
220
      break;
224
226
    }
225
342
    default:
226
342
      break;
227
854
    }
228
854
  }
229
230
65
  void VisitUnaryOperator(const UnaryOperator *S) {
231
65
    const Expr *SubExpr = S->getSubExpr();
232
65
    assert(SubExpr != nullptr);
233
234
0
    switch (S->getOpcode()) {
235
11
    case UO_Deref: {
236
      // Skip past a reference to handle dereference of a dependent pointer.
237
11
      const auto *SubExprVal = cast_or_null<PointerValue>(
238
11
          Env.getValue(*SubExpr, SkipPast::Reference));
239
11
      if (SubExprVal == nullptr)
240
0
        break;
241
242
11
      auto &Loc = Env.createStorageLocation(*S);
243
11
      Env.setStorageLocation(*S, Loc);
244
11
      Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
245
11
                            SubExprVal->getPointeeLoc())));
246
11
      break;
247
11
    }
248
14
    case UO_AddrOf: {
249
      // Do not form a pointer to a reference. If `SubExpr` is assigned a
250
      // `ReferenceValue` then form a value that points to the location of its
251
      // pointee.
252
14
      StorageLocation *PointeeLoc =
253
14
          Env.getStorageLocation(*SubExpr, SkipPast::Reference);
254
14
      if (PointeeLoc == nullptr)
255
0
        break;
256
257
14
      auto &PointerLoc = Env.createStorageLocation(*S);
258
14
      auto &PointerVal =
259
14
          Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
260
14
      Env.setStorageLocation(*S, PointerLoc);
261
14
      Env.setValue(PointerLoc, PointerVal);
262
14
      break;
263
14
    }
264
40
    case UO_LNot: {
265
40
      auto *SubExprVal =
266
40
          dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None));
267
40
      if (SubExprVal == nullptr)
268
0
        break;
269
270
40
      auto &ExprLoc = Env.createStorageLocation(*S);
271
40
      Env.setStorageLocation(*S, ExprLoc);
272
40
      Env.setValue(ExprLoc, Env.makeNot(*SubExprVal));
273
40
      break;
274
40
    }
275
0
    default:
276
0
      break;
277
65
    }
278
65
  }
279
280
18
  void VisitCXXThisExpr(const CXXThisExpr *S) {
281
18
    auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
282
18
    assert(ThisPointeeLoc != nullptr);
283
284
0
    auto &Loc = Env.createStorageLocation(*S);
285
18
    Env.setStorageLocation(*S, Loc);
286
18
    Env.setValue(Loc, Env.takeOwnership(
287
18
                          std::make_unique<PointerValue>(*ThisPointeeLoc)));
288
18
  }
289
290
540
  void VisitMemberExpr(const MemberExpr *S) {
291
540
    ValueDecl *Member = S->getMemberDecl();
292
540
    assert(Member != nullptr);
293
294
    // FIXME: Consider assigning pointer values to function member expressions.
295
540
    if (Member->isFunctionOrFunctionTemplate())
296
482
      return;
297
298
58
    if (auto *D = dyn_cast<VarDecl>(Member)) {
299
8
      if (D->hasGlobalStorage()) {
300
8
        auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None);
301
8
        if (VarDeclLoc == nullptr)
302
0
          return;
303
304
8
        if (VarDeclLoc->getType()->isReferenceType()) {
305
4
          Env.setStorageLocation(*S, *VarDeclLoc);
306
4
        } else {
307
4
          auto &Loc = Env.createStorageLocation(*S);
308
4
          Env.setStorageLocation(*S, Loc);
309
4
          Env.setValue(Loc, Env.takeOwnership(
310
4
                                std::make_unique<ReferenceValue>(*VarDeclLoc)));
311
4
        }
312
8
        return;
313
8
      }
314
8
    }
315
316
    // The receiver can be either a value or a pointer to a value. Skip past the
317
    // indirection to handle both cases.
318
50
    auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
319
50
        Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
320
50
    if (BaseLoc == nullptr)
321
12
      return;
322
323
    // FIXME: Add support for union types.
324
38
    if (BaseLoc->getType()->isUnionType())
325
2
      return;
326
327
36
    auto &MemberLoc = BaseLoc->getChild(*Member);
328
36
    if (MemberLoc.getType()->isReferenceType()) {
329
6
      Env.setStorageLocation(*S, MemberLoc);
330
30
    } else {
331
30
      auto &Loc = Env.createStorageLocation(*S);
332
30
      Env.setStorageLocation(*S, Loc);
333
30
      Env.setValue(
334
30
          Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
335
30
    }
336
36
  }
337
338
4
  void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
339
4
    const Expr *InitExpr = S->getExpr();
340
4
    assert(InitExpr != nullptr);
341
342
0
    Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
343
4
    if (InitExprVal == nullptr)
344
0
      return;
345
346
4
    const FieldDecl *Field = S->getField();
347
4
    assert(Field != nullptr);
348
349
0
    auto &ThisLoc =
350
4
        *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
351
4
    auto &FieldLoc = ThisLoc.getChild(*Field);
352
4
    Env.setValue(FieldLoc, *InitExprVal);
353
4
  }
354
355
380
  void VisitCXXConstructExpr(const CXXConstructExpr *S) {
356
380
    const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
357
380
    assert(ConstructorDecl != nullptr);
358
359
380
    if (ConstructorDecl->isCopyOrMoveConstructor()) {
360
82
      assert(S->getNumArgs() == 1);
361
362
0
      const Expr *Arg = S->getArg(0);
363
82
      assert(Arg != nullptr);
364
365
82
      if (S->isElidable()) {
366
2
        auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
367
2
        if (ArgLoc == nullptr)
368
0
          return;
369
370
2
        Env.setStorageLocation(*S, *ArgLoc);
371
80
      } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) {
372
80
        auto &Loc = Env.createStorageLocation(*S);
373
80
        Env.setStorageLocation(*S, Loc);
374
80
        Env.setValue(Loc, *ArgVal);
375
80
      }
376
82
      return;
377
82
    }
378
379
298
    auto &Loc = Env.createStorageLocation(*S);
380
298
    Env.setStorageLocation(*S, Loc);
381
298
    if (Value *Val = Env.createValue(S->getType()))
382
296
      Env.setValue(Loc, *Val);
383
298
  }
384
385
132
  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
386
132
    if (S->getOperator() == OO_Equal) {
387
70
      assert(S->getNumArgs() == 2);
388
389
0
      const Expr *Arg0 = S->getArg(0);
390
70
      assert(Arg0 != nullptr);
391
392
0
      const Expr *Arg1 = S->getArg(1);
393
70
      assert(Arg1 != nullptr);
394
395
      // Evaluate only copy and move assignment operators.
396
0
      auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
397
70
      auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
398
70
      if (Arg0Type != Arg1Type)
399
58
        return;
400
401
12
      auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);
402
12
      if (ObjectLoc == nullptr)
403
0
        return;
404
405
12
      auto *Val = Env.getValue(*Arg1, SkipPast::Reference);
406
12
      if (Val == nullptr)
407
0
        return;
408
409
      // Assign a value to the storage location of the object.
410
12
      Env.setValue(*ObjectLoc, *Val);
411
412
      // FIXME: Add a test for the value of the whole expression.
413
      // Assign a storage location for the whole expression.
414
12
      Env.setStorageLocation(*S, *ObjectLoc);
415
12
    }
416
132
  }
417
418
10
  void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
419
10
    if (S->getCastKind() == CK_ConstructorConversion) {
420
10
      const Expr *SubExpr = S->getSubExpr();
421
10
      assert(SubExpr != nullptr);
422
423
0
      auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
424
10
      if (SubExprLoc == nullptr)
425
0
        return;
426
427
10
      Env.setStorageLocation(*S, *SubExprLoc);
428
10
    }
429
10
  }
430
431
50
  void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
432
50
    auto &Loc = Env.createStorageLocation(*S);
433
50
    Env.setStorageLocation(*S, Loc);
434
50
    if (Value *Val = Env.createValue(S->getType()))
435
50
      Env.setValue(Loc, *Val);
436
50
  }
437
438
656
  void VisitCallExpr(const CallExpr *S) {
439
    // Of clang's builtins, only `__builtin_expect` is handled explicitly, since
440
    // others (like trap, debugtrap, and unreachable) are handled by CFG
441
    // construction.
442
656
    if (S->isCallToStdMove()) {
443
26
      assert(S->getNumArgs() == 1);
444
445
0
      const Expr *Arg = S->getArg(0);
446
26
      assert(Arg != nullptr);
447
448
0
      auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
449
26
      if (ArgLoc == nullptr)
450
0
        return;
451
452
26
      Env.setStorageLocation(*S, *ArgLoc);
453
630
    } else if (S->getDirectCallee() != nullptr &&
454
630
               S->getDirectCallee()->getBuiltinID() ==
455
630
                   Builtin::BI__builtin_expect) {
456
4
      assert(S->getNumArgs() > 0);
457
0
      assert(S->getArg(0) != nullptr);
458
      // `__builtin_expect` returns by-value, so strip away any potential
459
      // references in the argument.
460
0
      auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference);
461
4
      if (ArgLoc == nullptr)
462
0
        return;
463
4
      Env.setStorageLocation(*S, *ArgLoc);
464
4
    }
465
656
  }
466
467
262
  void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
468
262
    const Expr *SubExpr = S->getSubExpr();
469
262
    assert(SubExpr != nullptr);
470
471
0
    auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
472
262
    if (SubExprLoc == nullptr)
473
188
      return;
474
475
74
    Env.setStorageLocation(*S, *SubExprLoc);
476
74
  }
477
478
36
  void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
479
36
    const Expr *SubExpr = S->getSubExpr();
480
36
    assert(SubExpr != nullptr);
481
482
0
    auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
483
36
    if (SubExprLoc == nullptr)
484
20
      return;
485
486
16
    Env.setStorageLocation(*S, *SubExprLoc);
487
16
  }
488
489
2
  void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
490
2
    if (S->getCastKind() == CK_NoOp) {
491
2
      const Expr *SubExpr = S->getSubExpr();
492
2
      assert(SubExpr != nullptr);
493
494
0
      auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
495
2
      if (SubExprLoc == nullptr)
496
0
        return;
497
498
2
      Env.setStorageLocation(*S, *SubExprLoc);
499
2
    }
500
2
  }
501
502
24
  void VisitConditionalOperator(const ConditionalOperator *S) {
503
    // FIXME: Revisit this once flow conditions are added to the framework. For
504
    // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
505
    // condition.
506
24
    auto &Loc = Env.createStorageLocation(*S);
507
24
    Env.setStorageLocation(*S, Loc);
508
24
    if (Value *Val = Env.createValue(S->getType()))
509
16
      Env.setValue(Loc, *Val);
510
24
  }
511
512
20
  void VisitInitListExpr(const InitListExpr *S) {
513
20
    QualType Type = S->getType();
514
515
20
    auto &Loc = Env.createStorageLocation(*S);
516
20
    Env.setStorageLocation(*S, Loc);
517
518
20
    auto *Val = Env.createValue(Type);
519
20
    if (Val == nullptr)
520
12
      return;
521
522
8
    Env.setValue(Loc, *Val);
523
524
8
    if (Type->isStructureOrClassType()) {
525
16
      for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
526
16
        const FieldDecl *Field = std::get<0>(IT);
527
16
        assert(Field != nullptr);
528
529
0
        const Expr *Init = std::get<1>(IT);
530
16
        assert(Init != nullptr);
531
532
16
        if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
533
16
          cast<StructValue>(Val)->setChild(*Field, *InitVal);
534
16
      }
535
8
    }
536
    // FIXME: Implement array initialization.
537
8
  }
538
539
60
  void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
540
60
    auto &Loc = Env.createStorageLocation(*S);
541
60
    Env.setStorageLocation(*S, Loc);
542
60
    Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue()));
543
60
  }
544
545
8
  void VisitParenExpr(const ParenExpr *S) {
546
    // The CFG does not contain `ParenExpr` as top-level statements in basic
547
    // blocks, however manual traversal to sub-expressions may encounter them.
548
    // Redirect to the sub-expression.
549
8
    auto *SubExpr = S->getSubExpr();
550
8
    assert(SubExpr != nullptr);
551
0
    Visit(SubExpr);
552
8
  }
553
554
0
  void VisitExprWithCleanups(const ExprWithCleanups *S) {
555
    // The CFG does not contain `ExprWithCleanups` as top-level statements in
556
    // basic blocks, however manual traversal to sub-expressions may encounter
557
    // them. Redirect to the sub-expression.
558
0
    auto *SubExpr = S->getSubExpr();
559
0
    assert(SubExpr != nullptr);
560
0
    Visit(SubExpr);
561
0
  }
562
563
private:
564
48
  BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
565
    // `SubExpr` and its parent logic operator might be part of different basic
566
    // blocks. We try to access the value that is assigned to `SubExpr` in the
567
    // corresponding environment.
568
48
    if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) {
569
48
      if (auto *Val = dyn_cast_or_null<BoolValue>(
570
48
              SubExprEnv->getValue(SubExpr, SkipPast::Reference)))
571
44
        return *Val;
572
48
    }
573
574
    // Sub-expressions that are logic operators are not added in basic blocks
575
    // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic
576
    // operator, it isn't evaluated and assigned a value yet. In that case, we
577
    // need to first visit `SubExpr` and then try to get the value that gets
578
    // assigned to it.
579
4
    Visit(&SubExpr);
580
4
    if (auto *Val = dyn_cast_or_null<BoolValue>(
581
4
            Env.getValue(SubExpr, SkipPast::Reference)))
582
4
      return *Val;
583
584
    // If the value of `SubExpr` is still unknown, we create a fresh symbolic
585
    // boolean value for it.
586
0
    return Env.makeAtomicBoolValue();
587
4
  }
588
589
  const StmtToEnvMap &StmtToEnv;
590
  Environment &Env;
591
};
592
593
5.80k
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
594
5.80k
  TransferVisitor(StmtToEnv, Env).Visit(&S);
595
5.80k
}
596
597
} // namespace dataflow
598
} // namespace clang