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 const Expr *skipExprWithCleanups(const Expr *E) {
37   if (auto *C = dyn_cast_or_null<ExprWithCleanups>(E))
38     return C->getSubExpr();
39   return E;
40 }
41 
42 static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
43                                           Environment &Env) {
44   // Equality of booleans involves implicit integral casts. Ignore these casts
45   // for now and focus on the values associated with the wrapped expressions.
46   // FIXME: Consider changing this once the framework offers better support for
47   // integral casts.
48   const Expr *LHSNorm = LHS.IgnoreCasts();
49   const Expr *RHSNorm = RHS.IgnoreCasts();
50   assert(LHSNorm != nullptr);
51   assert(RHSNorm != nullptr);
52 
53   if (auto *LHSValue = dyn_cast_or_null<BoolValue>(
54           Env.getValue(*LHSNorm, SkipPast::Reference)))
55     if (auto *RHSValue = dyn_cast_or_null<BoolValue>(
56             Env.getValue(*RHSNorm, SkipPast::Reference)))
57       return Env.makeIff(*LHSValue, *RHSValue);
58 
59   return Env.makeAtomicBoolValue();
60 }
61 
62 class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
63 public:
64   TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
65       : StmtToEnv(StmtToEnv), Env(Env) {}
66 
67   void VisitBinaryOperator(const BinaryOperator *S) {
68     // The CFG does not contain `ParenExpr` as top-level statements in basic
69     // blocks, however sub-expressions can still be of that type.
70     assert(S->getLHS() != nullptr);
71     const Expr *LHS = S->getLHS()->IgnoreParens();
72     assert(LHS != nullptr);
73 
74     assert(S->getRHS() != nullptr);
75     const Expr *RHS = S->getRHS()->IgnoreParens();
76     assert(RHS != nullptr);
77 
78     switch (S->getOpcode()) {
79     case BO_Assign: {
80       auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
81       if (LHSLoc == nullptr)
82         break;
83 
84       auto *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
85       if (RHSVal == nullptr)
86         break;
87 
88       // Assign a value to the storage location of the left-hand side.
89       Env.setValue(*LHSLoc, *RHSVal);
90 
91       // Assign a storage location for the whole expression.
92       Env.setStorageLocation(*S, *LHSLoc);
93       break;
94     }
95     case BO_LAnd:
96     case BO_LOr: {
97       BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
98       BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
99 
100       auto &Loc = Env.createStorageLocation(*S);
101       Env.setStorageLocation(*S, Loc);
102       if (S->getOpcode() == BO_LAnd)
103         Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
104       else
105         Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
106       break;
107     }
108     case BO_NE:
109     case BO_EQ: {
110       auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
111       auto &Loc = Env.createStorageLocation(*S);
112       Env.setStorageLocation(*S, Loc);
113       Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue
114                                                 : Env.makeNot(LHSEqRHSValue));
115       break;
116     }
117     default:
118       break;
119     }
120   }
121 
122   void VisitDeclRefExpr(const DeclRefExpr *S) {
123     assert(S->getDecl() != nullptr);
124     auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
125     if (DeclLoc == nullptr)
126       return;
127 
128     if (S->getDecl()->getType()->isReferenceType()) {
129       Env.setStorageLocation(*S, *DeclLoc);
130     } else {
131       auto &Loc = Env.createStorageLocation(*S);
132       auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
133       Env.setStorageLocation(*S, Loc);
134       Env.setValue(Loc, Val);
135     }
136   }
137 
138   void VisitDeclStmt(const DeclStmt *S) {
139     // Group decls are converted into single decls in the CFG so the cast below
140     // is safe.
141     const auto &D = *cast<VarDecl>(S->getSingleDecl());
142 
143     // Static local vars are already initialized in `Environment`.
144     if (D.hasGlobalStorage())
145       return;
146 
147     auto &Loc = Env.createStorageLocation(D);
148     Env.setStorageLocation(D, Loc);
149 
150     const Expr *InitExpr = D.getInit();
151     if (InitExpr == nullptr) {
152       // No initializer expression - associate `Loc` with a new value.
153       if (Value *Val = Env.createValue(D.getType()))
154         Env.setValue(Loc, *Val);
155       return;
156     }
157 
158     // The CFG does not contain `ParenExpr` as top-level statements in basic
159     // blocks, however sub-expressions can still be of that type.
160     InitExpr = skipExprWithCleanups(D.getInit()->IgnoreParens());
161     assert(InitExpr != nullptr);
162 
163     if (D.getType()->isReferenceType()) {
164       // Initializing a reference variable - do not create a reference to
165       // reference.
166       if (auto *InitExprLoc =
167               Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
168         auto &Val =
169             Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
170         Env.setValue(Loc, Val);
171         return;
172       }
173     } else if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
174       Env.setValue(Loc, *InitExprVal);
175       return;
176     }
177 
178     // We arrive here in (the few) cases where an expression is intentionally
179     // "uninterpreted". There are two ways to handle this situation: propagate
180     // the status, so that uninterpreted initializers result in uninterpreted
181     // variables, or provide a default value. We choose the latter so that later
182     // refinements of the variable can be used for reasoning about the
183     // surrounding code.
184     //
185     // FIXME. If and when we interpret all language cases, change this to assert
186     // that `InitExpr` is interpreted, rather than supplying a default value
187     // (assuming we don't update the environment API to return references).
188     if (Value *Val = Env.createValue(D.getType()))
189       Env.setValue(Loc, *Val);
190   }
191 
192   void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
193     // The CFG does not contain `ParenExpr` as top-level statements in basic
194     // blocks, however sub-expressions can still be of that type.
195     assert(S->getSubExpr() != nullptr);
196     const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
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     // The CFG does not contain `ParenExpr` as top-level statements in basic
256     // blocks, however sub-expressions can still be of that type.
257     assert(S->getSubExpr() != nullptr);
258     const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
259     assert(SubExpr != nullptr);
260 
261     switch (S->getOpcode()) {
262     case UO_Deref: {
263       // Skip past a reference to handle dereference of a dependent pointer.
264       const auto *SubExprVal = cast_or_null<PointerValue>(
265           Env.getValue(*SubExpr, SkipPast::Reference));
266       if (SubExprVal == nullptr)
267         break;
268 
269       auto &Loc = Env.createStorageLocation(*S);
270       Env.setStorageLocation(*S, Loc);
271       Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
272                             SubExprVal->getPointeeLoc())));
273       break;
274     }
275     case UO_AddrOf: {
276       // Do not form a pointer to a reference. If `SubExpr` is assigned a
277       // `ReferenceValue` then form a value that points to the location of its
278       // pointee.
279       StorageLocation *PointeeLoc =
280           Env.getStorageLocation(*SubExpr, SkipPast::Reference);
281       if (PointeeLoc == nullptr)
282         break;
283 
284       auto &PointerLoc = Env.createStorageLocation(*S);
285       auto &PointerVal =
286           Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
287       Env.setStorageLocation(*S, PointerLoc);
288       Env.setValue(PointerLoc, PointerVal);
289       break;
290     }
291     case UO_LNot: {
292       auto *SubExprVal =
293           dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None));
294       if (SubExprVal == nullptr)
295         break;
296 
297       auto &ExprLoc = Env.createStorageLocation(*S);
298       Env.setStorageLocation(*S, ExprLoc);
299       Env.setValue(ExprLoc, Env.makeNot(*SubExprVal));
300       break;
301     }
302     default:
303       break;
304     }
305   }
306 
307   void VisitCXXThisExpr(const CXXThisExpr *S) {
308     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
309     assert(ThisPointeeLoc != nullptr);
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       // The CFG does not contain `ParenExpr` as top-level statements in basic
448       // blocks, however sub-expressions can still be of that type.
449       assert(S->getSubExpr() != nullptr);
450       const Expr *SubExpr = S->getSubExpr();
451       assert(SubExpr != nullptr);
452 
453       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
454       if (SubExprLoc == nullptr)
455         return;
456 
457       Env.setStorageLocation(*S, *SubExprLoc);
458     }
459   }
460 
461   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
462     auto &Loc = Env.createStorageLocation(*S);
463     Env.setStorageLocation(*S, Loc);
464     if (Value *Val = Env.createValue(S->getType()))
465       Env.setValue(Loc, *Val);
466   }
467 
468   void VisitCallExpr(const CallExpr *S) {
469     // Of clang's builtins, only `__builtin_expect` is handled explicitly, since
470     // others (like trap, debugtrap, and unreachable) are handled by CFG
471     // construction.
472     if (S->isCallToStdMove()) {
473       assert(S->getNumArgs() == 1);
474 
475       const Expr *Arg = S->getArg(0);
476       assert(Arg != nullptr);
477 
478       auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
479       if (ArgLoc == nullptr)
480         return;
481 
482       Env.setStorageLocation(*S, *ArgLoc);
483     } else if (S->getDirectCallee() != nullptr &&
484                S->getDirectCallee()->getBuiltinID() ==
485                    Builtin::BI__builtin_expect) {
486       assert(S->getNumArgs() > 0);
487       assert(S->getArg(0) != nullptr);
488       // `__builtin_expect` returns by-value, so strip away any potential
489       // references in the argument.
490       auto *ArgLoc = Env.getStorageLocation(
491           *S->getArg(0)->IgnoreParenImpCasts(), SkipPast::Reference);
492       if (ArgLoc == nullptr)
493         return;
494       Env.setStorageLocation(*S, *ArgLoc);
495     }
496   }
497 
498   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
499     const Expr *SubExpr = S->getSubExpr();
500     assert(SubExpr != nullptr);
501 
502     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
503     if (SubExprLoc == nullptr)
504       return;
505 
506     Env.setStorageLocation(*S, *SubExprLoc);
507   }
508 
509   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *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 VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
521     if (S->getCastKind() == CK_NoOp) {
522       const Expr *SubExpr = S->getSubExpr();
523       assert(SubExpr != nullptr);
524 
525       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
526       if (SubExprLoc == nullptr)
527         return;
528 
529       Env.setStorageLocation(*S, *SubExprLoc);
530     }
531   }
532 
533   void VisitConditionalOperator(const ConditionalOperator *S) {
534     // FIXME: Revisit this once flow conditions are added to the framework. For
535     // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
536     // condition.
537     auto &Loc = Env.createStorageLocation(*S);
538     Env.setStorageLocation(*S, Loc);
539     if (Value *Val = Env.createValue(S->getType()))
540       Env.setValue(Loc, *Val);
541   }
542 
543   void VisitInitListExpr(const InitListExpr *S) {
544     QualType Type = S->getType();
545 
546     auto &Loc = Env.createStorageLocation(*S);
547     Env.setStorageLocation(*S, Loc);
548 
549     auto *Val = Env.createValue(Type);
550     if (Val == nullptr)
551       return;
552 
553     Env.setValue(Loc, *Val);
554 
555     if (Type->isStructureOrClassType()) {
556       for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
557         const FieldDecl *Field = std::get<0>(IT);
558         assert(Field != nullptr);
559 
560         const Expr *Init = std::get<1>(IT);
561         assert(Init != nullptr);
562 
563         if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
564           cast<StructValue>(Val)->setChild(*Field, *InitVal);
565       }
566     }
567     // FIXME: Implement array initialization.
568   }
569 
570   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
571     auto &Loc = Env.createStorageLocation(*S);
572     Env.setStorageLocation(*S, Loc);
573     Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue()));
574   }
575 
576 private:
577   BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
578     // `SubExpr` and its parent logic operator might be part of different basic
579     // blocks. We try to access the value that is assigned to `SubExpr` in the
580     // corresponding environment.
581     if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) {
582       if (auto *Val = dyn_cast_or_null<BoolValue>(
583               SubExprEnv->getValue(SubExpr, SkipPast::Reference)))
584         return *Val;
585     }
586 
587     // Sub-expressions that are logic operators are not added in basic blocks
588     // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic
589     // operator, it isn't evaluated and assigned a value yet. In that case, we
590     // need to first visit `SubExpr` and then try to get the value that gets
591     // assigned to it.
592     Visit(&SubExpr);
593     if (auto *Val = dyn_cast_or_null<BoolValue>(
594             Env.getValue(SubExpr, SkipPast::Reference)))
595       return *Val;
596 
597     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
598     // boolean value for it.
599     return Env.makeAtomicBoolValue();
600   }
601 
602   const StmtToEnvMap &StmtToEnv;
603   Environment &Env;
604 };
605 
606 void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
607   assert(!isa<ParenExpr>(&S));
608   TransferVisitor(StmtToEnv, Env).Visit(&S);
609 }
610 
611 } // namespace dataflow
612 } // namespace clang
613