Coverage Report

Created: 2022-07-16 07:03

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