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