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