xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp (revision 753f127f3ace09432b2baeffd71a308760641a62)
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     case CK_NullToPointer:
255     case CK_NullToMemberPointer: {
256       auto &Loc = Env.createStorageLocation(S->getType());
257       Env.setStorageLocation(*S, Loc);
258 
259       auto &NullPointerVal =
260           Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
261       Env.setValue(Loc, NullPointerVal);
262       break;
263     }
264     default:
265       break;
266     }
267   }
268 
269   void VisitUnaryOperator(const UnaryOperator *S) {
270     const Expr *SubExpr = S->getSubExpr();
271     assert(SubExpr != nullptr);
272 
273     switch (S->getOpcode()) {
274     case UO_Deref: {
275       // Skip past a reference to handle dereference of a dependent pointer.
276       const auto *SubExprVal = cast_or_null<PointerValue>(
277           Env.getValue(*SubExpr, SkipPast::Reference));
278       if (SubExprVal == nullptr)
279         break;
280 
281       auto &Loc = Env.createStorageLocation(*S);
282       Env.setStorageLocation(*S, Loc);
283       Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
284                             SubExprVal->getPointeeLoc())));
285       break;
286     }
287     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       StorageLocation *PointeeLoc =
292           Env.getStorageLocation(*SubExpr, SkipPast::Reference);
293       if (PointeeLoc == nullptr)
294         break;
295 
296       auto &PointerLoc = Env.createStorageLocation(*S);
297       auto &PointerVal =
298           Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
299       Env.setStorageLocation(*S, PointerLoc);
300       Env.setValue(PointerLoc, PointerVal);
301       break;
302     }
303     case UO_LNot: {
304       auto *SubExprVal =
305           dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None));
306       if (SubExprVal == nullptr)
307         break;
308 
309       auto &ExprLoc = Env.createStorageLocation(*S);
310       Env.setStorageLocation(*S, ExprLoc);
311       Env.setValue(ExprLoc, Env.makeNot(*SubExprVal));
312       break;
313     }
314     default:
315       break;
316     }
317   }
318 
319   void VisitCXXThisExpr(const CXXThisExpr *S) {
320     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
321     if (ThisPointeeLoc == nullptr)
322       // Unions are not supported yet, and will not have a location for the
323       // `this` expression's pointee.
324       return;
325 
326     auto &Loc = Env.createStorageLocation(*S);
327     Env.setStorageLocation(*S, Loc);
328     Env.setValue(Loc, Env.takeOwnership(
329                           std::make_unique<PointerValue>(*ThisPointeeLoc)));
330   }
331 
332   void VisitMemberExpr(const MemberExpr *S) {
333     ValueDecl *Member = S->getMemberDecl();
334     assert(Member != nullptr);
335 
336     // FIXME: Consider assigning pointer values to function member expressions.
337     if (Member->isFunctionOrFunctionTemplate())
338       return;
339 
340     if (auto *D = dyn_cast<VarDecl>(Member)) {
341       if (D->hasGlobalStorage()) {
342         auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None);
343         if (VarDeclLoc == nullptr)
344           return;
345 
346         if (VarDeclLoc->getType()->isReferenceType()) {
347           Env.setStorageLocation(*S, *VarDeclLoc);
348         } else {
349           auto &Loc = Env.createStorageLocation(*S);
350           Env.setStorageLocation(*S, Loc);
351           Env.setValue(Loc, Env.takeOwnership(
352                                 std::make_unique<ReferenceValue>(*VarDeclLoc)));
353         }
354         return;
355       }
356     }
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     auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
361         Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
362     if (BaseLoc == nullptr)
363       return;
364 
365     // FIXME: Add support for union types.
366     if (BaseLoc->getType()->isUnionType())
367       return;
368 
369     auto &MemberLoc = BaseLoc->getChild(*Member);
370     if (MemberLoc.getType()->isReferenceType()) {
371       Env.setStorageLocation(*S, MemberLoc);
372     } else {
373       auto &Loc = Env.createStorageLocation(*S);
374       Env.setStorageLocation(*S, Loc);
375       Env.setValue(
376           Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
377     }
378   }
379 
380   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
381     const Expr *InitExpr = S->getExpr();
382     assert(InitExpr != nullptr);
383 
384     Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
385     if (InitExprVal == nullptr)
386       return;
387 
388     const FieldDecl *Field = S->getField();
389     assert(Field != nullptr);
390 
391     auto &ThisLoc =
392         *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
393     auto &FieldLoc = ThisLoc.getChild(*Field);
394     Env.setValue(FieldLoc, *InitExprVal);
395   }
396 
397   void VisitCXXConstructExpr(const CXXConstructExpr *S) {
398     const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
399     assert(ConstructorDecl != nullptr);
400 
401     if (ConstructorDecl->isCopyOrMoveConstructor()) {
402       assert(S->getNumArgs() == 1);
403 
404       const Expr *Arg = S->getArg(0);
405       assert(Arg != nullptr);
406 
407       if (S->isElidable()) {
408         auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
409         if (ArgLoc == nullptr)
410           return;
411 
412         Env.setStorageLocation(*S, *ArgLoc);
413       } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) {
414         auto &Loc = Env.createStorageLocation(*S);
415         Env.setStorageLocation(*S, Loc);
416         Env.setValue(Loc, *ArgVal);
417       }
418       return;
419     }
420 
421     auto &Loc = Env.createStorageLocation(*S);
422     Env.setStorageLocation(*S, Loc);
423     if (Value *Val = Env.createValue(S->getType()))
424       Env.setValue(Loc, *Val);
425   }
426 
427   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
428     if (S->getOperator() == OO_Equal) {
429       assert(S->getNumArgs() == 2);
430 
431       const Expr *Arg0 = S->getArg(0);
432       assert(Arg0 != nullptr);
433 
434       const Expr *Arg1 = S->getArg(1);
435       assert(Arg1 != nullptr);
436 
437       // Evaluate only copy and move assignment operators.
438       auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
439       auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
440       if (Arg0Type != Arg1Type)
441         return;
442 
443       auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);
444       if (ObjectLoc == nullptr)
445         return;
446 
447       auto *Val = Env.getValue(*Arg1, SkipPast::Reference);
448       if (Val == nullptr)
449         return;
450 
451       // Assign a value to the storage location of the object.
452       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       Env.setStorageLocation(*S, *ObjectLoc);
457     }
458   }
459 
460   void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
461     if (S->getCastKind() == CK_ConstructorConversion) {
462       const Expr *SubExpr = S->getSubExpr();
463       assert(SubExpr != nullptr);
464 
465       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
466       if (SubExprLoc == nullptr)
467         return;
468 
469       Env.setStorageLocation(*S, *SubExprLoc);
470     }
471   }
472 
473   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
474     auto &Loc = Env.createStorageLocation(*S);
475     Env.setStorageLocation(*S, Loc);
476     if (Value *Val = Env.createValue(S->getType()))
477       Env.setValue(Loc, *Val);
478   }
479 
480   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     if (S->isCallToStdMove()) {
485       assert(S->getNumArgs() == 1);
486 
487       const Expr *Arg = S->getArg(0);
488       assert(Arg != nullptr);
489 
490       auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
491       if (ArgLoc == nullptr)
492         return;
493 
494       Env.setStorageLocation(*S, *ArgLoc);
495     } else if (S->getDirectCallee() != nullptr &&
496                S->getDirectCallee()->getBuiltinID() ==
497                    Builtin::BI__builtin_expect) {
498       assert(S->getNumArgs() > 0);
499       assert(S->getArg(0) != nullptr);
500       // `__builtin_expect` returns by-value, so strip away any potential
501       // references in the argument.
502       auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference);
503       if (ArgLoc == nullptr)
504         return;
505       Env.setStorageLocation(*S, *ArgLoc);
506     }
507   }
508 
509   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
510     const Expr *SubExpr = S->getSubExpr();
511     assert(SubExpr != nullptr);
512 
513     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
514     if (SubExprLoc == nullptr)
515       return;
516 
517     Env.setStorageLocation(*S, *SubExprLoc);
518   }
519 
520   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
521     const Expr *SubExpr = S->getSubExpr();
522     assert(SubExpr != nullptr);
523 
524     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
525     if (SubExprLoc == nullptr)
526       return;
527 
528     Env.setStorageLocation(*S, *SubExprLoc);
529   }
530 
531   void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
532     if (S->getCastKind() == CK_NoOp) {
533       const Expr *SubExpr = S->getSubExpr();
534       assert(SubExpr != nullptr);
535 
536       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
537       if (SubExprLoc == nullptr)
538         return;
539 
540       Env.setStorageLocation(*S, *SubExprLoc);
541     }
542   }
543 
544   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     auto &Loc = Env.createStorageLocation(*S);
549     Env.setStorageLocation(*S, Loc);
550     if (Value *Val = Env.createValue(S->getType()))
551       Env.setValue(Loc, *Val);
552   }
553 
554   void VisitInitListExpr(const InitListExpr *S) {
555     QualType Type = S->getType();
556 
557     auto &Loc = Env.createStorageLocation(*S);
558     Env.setStorageLocation(*S, Loc);
559 
560     auto *Val = Env.createValue(Type);
561     if (Val == nullptr)
562       return;
563 
564     Env.setValue(Loc, *Val);
565 
566     if (Type->isStructureOrClassType()) {
567       for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
568         const FieldDecl *Field = std::get<0>(IT);
569         assert(Field != nullptr);
570 
571         const Expr *Init = std::get<1>(IT);
572         assert(Init != nullptr);
573 
574         if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
575           cast<StructValue>(Val)->setChild(*Field, *InitVal);
576       }
577     }
578     // FIXME: Implement array initialization.
579   }
580 
581   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
582     auto &Loc = Env.createStorageLocation(*S);
583     Env.setStorageLocation(*S, Loc);
584     Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue()));
585   }
586 
587   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     auto *SubExpr = S->getSubExpr();
592     assert(SubExpr != nullptr);
593     Visit(SubExpr);
594   }
595 
596   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     auto *SubExpr = S->getSubExpr();
601     assert(SubExpr != nullptr);
602     Visit(SubExpr);
603   }
604 
605 private:
606   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     if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) {
611       if (auto *Val = dyn_cast_or_null<BoolValue>(
612               SubExprEnv->getValue(SubExpr, SkipPast::Reference)))
613         return *Val;
614     }
615 
616     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       Visit(&SubExpr);
623     }
624 
625     if (auto *Val = dyn_cast_or_null<BoolValue>(
626             Env.getValue(SubExpr, SkipPast::Reference)))
627       return *Val;
628 
629     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
630     // boolean value for it.
631     return Env.makeAtomicBoolValue();
632   }
633 
634   const StmtToEnvMap &StmtToEnv;
635   Environment &Env;
636 };
637 
638 void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
639   TransferVisitor(StmtToEnv, Env).Visit(&S);
640 }
641 
642 } // namespace dataflow
643 } // namespace clang
644