1af7bc39bSStanislav Gatev //===-- Transfer.cpp --------------------------------------------*- C++ -*-===//
2af7bc39bSStanislav Gatev //
3af7bc39bSStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af7bc39bSStanislav Gatev // See https://llvm.org/LICENSE.txt for license information.
5af7bc39bSStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af7bc39bSStanislav Gatev //
7af7bc39bSStanislav Gatev //===----------------------------------------------------------------------===//
8af7bc39bSStanislav Gatev //
9af7bc39bSStanislav Gatev //  This file defines transfer functions that evaluate program statements and
10af7bc39bSStanislav Gatev //  update an environment accordingly.
11af7bc39bSStanislav Gatev //
12af7bc39bSStanislav Gatev //===----------------------------------------------------------------------===//
13af7bc39bSStanislav Gatev 
14af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/Transfer.h"
15af7bc39bSStanislav Gatev #include "clang/AST/Decl.h"
16af7bc39bSStanislav Gatev #include "clang/AST/DeclBase.h"
177d941d6dSStanislav Gatev #include "clang/AST/DeclCXX.h"
18af7bc39bSStanislav Gatev #include "clang/AST/Expr.h"
1999f7d55eSStanislav Gatev #include "clang/AST/ExprCXX.h"
20e7481f6eSStanislav Gatev #include "clang/AST/OperationKinds.h"
21af7bc39bSStanislav Gatev #include "clang/AST/Stmt.h"
22af7bc39bSStanislav Gatev #include "clang/AST/StmtVisitor.h"
23*300fbf56SSam Estep #include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
24af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
25*300fbf56SSam Estep #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
26ef1e1b31SYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/Value.h"
27506ec85bSYitzhak Mandelbaum #include "clang/Basic/Builtins.h"
28e7481f6eSStanislav Gatev #include "clang/Basic/OperatorKinds.h"
2964ba462bSStanislav Gatev #include "llvm/ADT/STLExtras.h"
30af7bc39bSStanislav Gatev #include "llvm/Support/Casting.h"
31af7bc39bSStanislav Gatev #include <cassert>
32e7481f6eSStanislav Gatev #include <memory>
3364ba462bSStanislav Gatev #include <tuple>
34af7bc39bSStanislav Gatev 
35af7bc39bSStanislav Gatev namespace clang {
36af7bc39bSStanislav Gatev namespace dataflow {
37af7bc39bSStanislav Gatev 
evaluateBooleanEquality(const Expr & LHS,const Expr & RHS,Environment & Env)38ef1e1b31SYitzhak Mandelbaum static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
39ef1e1b31SYitzhak Mandelbaum                                           Environment &Env) {
4045643cfcSEric Li   if (auto *LHSValue =
4145643cfcSEric Li           dyn_cast_or_null<BoolValue>(Env.getValue(LHS, SkipPast::Reference)))
4245643cfcSEric Li     if (auto *RHSValue =
4345643cfcSEric Li             dyn_cast_or_null<BoolValue>(Env.getValue(RHS, SkipPast::Reference)))
44ef1e1b31SYitzhak Mandelbaum       return Env.makeIff(*LHSValue, *RHSValue);
45ef1e1b31SYitzhak Mandelbaum 
46ef1e1b31SYitzhak Mandelbaum   return Env.makeAtomicBoolValue();
47ef1e1b31SYitzhak Mandelbaum }
48ef1e1b31SYitzhak Mandelbaum 
49af7bc39bSStanislav Gatev class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
50af7bc39bSStanislav Gatev public:
TransferVisitor(const StmtToEnvMap & StmtToEnv,Environment & Env,TransferOptions Options)51*300fbf56SSam Estep   TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
52*300fbf56SSam Estep                   TransferOptions Options)
53*300fbf56SSam Estep       : StmtToEnv(StmtToEnv), Env(Env), Options(Options) {}
54af7bc39bSStanislav Gatev 
VisitBinaryOperator(const BinaryOperator * S)55e7481f6eSStanislav Gatev   void VisitBinaryOperator(const BinaryOperator *S) {
5645643cfcSEric Li     const Expr *LHS = S->getLHS();
57e7481f6eSStanislav Gatev     assert(LHS != nullptr);
58cf63e9d4SStanislav Gatev 
5945643cfcSEric Li     const Expr *RHS = S->getRHS();
60cf63e9d4SStanislav Gatev     assert(RHS != nullptr);
61cf63e9d4SStanislav Gatev 
62cf63e9d4SStanislav Gatev     switch (S->getOpcode()) {
63cf63e9d4SStanislav Gatev     case BO_Assign: {
64e7481f6eSStanislav Gatev       auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
65e7481f6eSStanislav Gatev       if (LHSLoc == nullptr)
66dd4dde8dSStanislav Gatev         break;
67e7481f6eSStanislav Gatev 
68cf63e9d4SStanislav Gatev       auto *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
69e7481f6eSStanislav Gatev       if (RHSVal == nullptr)
70dd4dde8dSStanislav Gatev         break;
71e7481f6eSStanislav Gatev 
72e7481f6eSStanislav Gatev       // Assign a value to the storage location of the left-hand side.
73e7481f6eSStanislav Gatev       Env.setValue(*LHSLoc, *RHSVal);
74e7481f6eSStanislav Gatev 
75e7481f6eSStanislav Gatev       // Assign a storage location for the whole expression.
76e7481f6eSStanislav Gatev       Env.setStorageLocation(*S, *LHSLoc);
77dd4dde8dSStanislav Gatev       break;
78e7481f6eSStanislav Gatev     }
79dd4dde8dSStanislav Gatev     case BO_LAnd:
80dd4dde8dSStanislav Gatev     case BO_LOr: {
81cf63e9d4SStanislav Gatev       BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
82cf63e9d4SStanislav Gatev       BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
83dd4dde8dSStanislav Gatev 
84dd4dde8dSStanislav Gatev       auto &Loc = Env.createStorageLocation(*S);
85dd4dde8dSStanislav Gatev       Env.setStorageLocation(*S, Loc);
86dd4dde8dSStanislav Gatev       if (S->getOpcode() == BO_LAnd)
87cf63e9d4SStanislav Gatev         Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
88dd4dde8dSStanislav Gatev       else
89cf63e9d4SStanislav Gatev         Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
90dd4dde8dSStanislav Gatev       break;
91dd4dde8dSStanislav Gatev     }
92ef1e1b31SYitzhak Mandelbaum     case BO_NE:
93ef1e1b31SYitzhak Mandelbaum     case BO_EQ: {
94ef1e1b31SYitzhak Mandelbaum       auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
95ef1e1b31SYitzhak Mandelbaum       auto &Loc = Env.createStorageLocation(*S);
96ef1e1b31SYitzhak Mandelbaum       Env.setStorageLocation(*S, Loc);
97ef1e1b31SYitzhak Mandelbaum       Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue
98ef1e1b31SYitzhak Mandelbaum                                                 : Env.makeNot(LHSEqRHSValue));
99ef1e1b31SYitzhak Mandelbaum       break;
100ef1e1b31SYitzhak Mandelbaum     }
101ba53906cSStanislav Gatev     case BO_Comma: {
102ba53906cSStanislav Gatev       if (auto *Loc = Env.getStorageLocation(*RHS, SkipPast::None))
103ba53906cSStanislav Gatev         Env.setStorageLocation(*S, *Loc);
104ba53906cSStanislav Gatev       break;
105ba53906cSStanislav Gatev     }
106dd4dde8dSStanislav Gatev     default:
107dd4dde8dSStanislav Gatev       break;
108dd4dde8dSStanislav Gatev     }
109e7481f6eSStanislav Gatev   }
110e7481f6eSStanislav Gatev 
VisitDeclRefExpr(const DeclRefExpr * S)111e7481f6eSStanislav Gatev   void VisitDeclRefExpr(const DeclRefExpr *S) {
112e7481f6eSStanislav Gatev     assert(S->getDecl() != nullptr);
113e7481f6eSStanislav Gatev     auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
114e7481f6eSStanislav Gatev     if (DeclLoc == nullptr)
115e7481f6eSStanislav Gatev       return;
116e7481f6eSStanislav Gatev 
117e7481f6eSStanislav Gatev     if (S->getDecl()->getType()->isReferenceType()) {
118e7481f6eSStanislav Gatev       Env.setStorageLocation(*S, *DeclLoc);
119e7481f6eSStanislav Gatev     } else {
120e7481f6eSStanislav Gatev       auto &Loc = Env.createStorageLocation(*S);
121e7481f6eSStanislav Gatev       auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
122e7481f6eSStanislav Gatev       Env.setStorageLocation(*S, Loc);
123e7481f6eSStanislav Gatev       Env.setValue(Loc, Val);
124e7481f6eSStanislav Gatev     }
125e7481f6eSStanislav Gatev   }
126e7481f6eSStanislav Gatev 
VisitDeclStmt(const DeclStmt * S)127af7bc39bSStanislav Gatev   void VisitDeclStmt(const DeclStmt *S) {
12837e6496cSStanislav Gatev     // Group decls are converted into single decls in the CFG so the cast below
12937e6496cSStanislav Gatev     // is safe.
13037e6496cSStanislav Gatev     const auto &D = *cast<VarDecl>(S->getSingleDecl());
13103dff121SStanislav Gatev 
13203dff121SStanislav Gatev     // Static local vars are already initialized in `Environment`.
13303dff121SStanislav Gatev     if (D.hasGlobalStorage())
13403dff121SStanislav Gatev       return;
13503dff121SStanislav Gatev 
13637e6496cSStanislav Gatev     auto &Loc = Env.createStorageLocation(D);
13737e6496cSStanislav Gatev     Env.setStorageLocation(D, Loc);
13837e6496cSStanislav Gatev 
13937e6496cSStanislav Gatev     const Expr *InitExpr = D.getInit();
14037e6496cSStanislav Gatev     if (InitExpr == nullptr) {
14137e6496cSStanislav Gatev       // No initializer expression - associate `Loc` with a new value.
142782eced5SStanislav Gatev       if (Value *Val = Env.createValue(D.getType()))
143782eced5SStanislav Gatev         Env.setValue(Loc, *Val);
14437e6496cSStanislav Gatev       return;
145af7bc39bSStanislav Gatev     }
14637e6496cSStanislav Gatev 
14737e6496cSStanislav Gatev     if (D.getType()->isReferenceType()) {
14837e6496cSStanislav Gatev       // Initializing a reference variable - do not create a reference to
14937e6496cSStanislav Gatev       // reference.
15037e6496cSStanislav Gatev       if (auto *InitExprLoc =
15137e6496cSStanislav Gatev               Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
15237e6496cSStanislav Gatev         auto &Val =
15337e6496cSStanislav Gatev             Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
15437e6496cSStanislav Gatev         Env.setValue(Loc, Val);
15537e6496cSStanislav Gatev       }
156eb2131bdSYitzhak Mandelbaum     } else if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
157eb2131bdSYitzhak Mandelbaum       Env.setValue(Loc, *InitExprVal);
15837e6496cSStanislav Gatev     }
15937e6496cSStanislav Gatev 
1600e286b77SStanislav Gatev     if (Env.getValue(Loc) == nullptr) {
161eb2131bdSYitzhak Mandelbaum       // We arrive here in (the few) cases where an expression is intentionally
162eb2131bdSYitzhak Mandelbaum       // "uninterpreted". There are two ways to handle this situation: propagate
163eb2131bdSYitzhak Mandelbaum       // the status, so that uninterpreted initializers result in uninterpreted
1640e286b77SStanislav Gatev       // variables, or provide a default value. We choose the latter so that
1650e286b77SStanislav Gatev       // later refinements of the variable can be used for reasoning about the
166eb2131bdSYitzhak Mandelbaum       // surrounding code.
167eb2131bdSYitzhak Mandelbaum       //
1680e286b77SStanislav Gatev       // FIXME. If and when we interpret all language cases, change this to
1690e286b77SStanislav Gatev       // assert that `InitExpr` is interpreted, rather than supplying a default
1700e286b77SStanislav Gatev       // value (assuming we don't update the environment API to return
1710e286b77SStanislav Gatev       // references).
172782eced5SStanislav Gatev       if (Value *Val = Env.createValue(D.getType()))
173782eced5SStanislav Gatev         Env.setValue(Loc, *Val);
174af7bc39bSStanislav Gatev     }
175af7bc39bSStanislav Gatev 
1760e286b77SStanislav Gatev     if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) {
1770e286b77SStanislav Gatev       // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This
1780e286b77SStanislav Gatev       // needs to be evaluated after initializing the values in the storage for
1790e286b77SStanislav Gatev       // VarDecl, as the bindings refer to them.
1800e286b77SStanislav Gatev       // FIXME: Add support for ArraySubscriptExpr.
1810e286b77SStanislav Gatev       // FIXME: Consider adding AST nodes that are used for structured bindings
1820e286b77SStanislav Gatev       // to the CFG.
1830e286b77SStanislav Gatev       for (const auto *B : Decomp->bindings()) {
1840e286b77SStanislav Gatev         auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding());
1850e286b77SStanislav Gatev         if (ME == nullptr)
1860e286b77SStanislav Gatev           continue;
1870e286b77SStanislav Gatev 
1880e286b77SStanislav Gatev         auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());
1890e286b77SStanislav Gatev         if (DE == nullptr)
1900e286b77SStanislav Gatev           continue;
1910e286b77SStanislav Gatev 
1920e286b77SStanislav Gatev         // ME and its base haven't been visited because they aren't included in
1930e286b77SStanislav Gatev         // the statements of the CFG basic block.
1940e286b77SStanislav Gatev         VisitDeclRefExpr(DE);
1950e286b77SStanislav Gatev         VisitMemberExpr(ME);
1960e286b77SStanislav Gatev 
1970e286b77SStanislav Gatev         if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference))
1980e286b77SStanislav Gatev           Env.setStorageLocation(*B, *Loc);
1990e286b77SStanislav Gatev       }
2000e286b77SStanislav Gatev     }
2010e286b77SStanislav Gatev   }
2020e286b77SStanislav Gatev 
VisitImplicitCastExpr(const ImplicitCastExpr * S)203e7481f6eSStanislav Gatev   void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
20462b2a47aSEric Li     const Expr *SubExpr = S->getSubExpr();
205e7481f6eSStanislav Gatev     assert(SubExpr != nullptr);
2067d941d6dSStanislav Gatev 
2077d941d6dSStanislav Gatev     switch (S->getCastKind()) {
208d002495bSYitzhak Mandelbaum     case CK_IntegralToBoolean: {
209d002495bSYitzhak Mandelbaum       // This cast creates a new, boolean value from the integral value. We
210d002495bSYitzhak Mandelbaum       // model that with a fresh value in the environment, unless it's already a
211d002495bSYitzhak Mandelbaum       // boolean.
212d002495bSYitzhak Mandelbaum       auto &Loc = Env.createStorageLocation(*S);
213d002495bSYitzhak Mandelbaum       Env.setStorageLocation(*S, Loc);
214d002495bSYitzhak Mandelbaum       if (auto *SubExprVal = dyn_cast_or_null<BoolValue>(
215d002495bSYitzhak Mandelbaum               Env.getValue(*SubExpr, SkipPast::Reference)))
216d002495bSYitzhak Mandelbaum         Env.setValue(Loc, *SubExprVal);
217d002495bSYitzhak Mandelbaum       else
218d002495bSYitzhak Mandelbaum         // FIXME: If integer modeling is added, then update this code to create
219d002495bSYitzhak Mandelbaum         // the boolean based on the integer model.
220d002495bSYitzhak Mandelbaum         Env.setValue(Loc, Env.makeAtomicBoolValue());
221d002495bSYitzhak Mandelbaum       break;
222d002495bSYitzhak Mandelbaum     }
223d002495bSYitzhak Mandelbaum 
2247d941d6dSStanislav Gatev     case CK_LValueToRValue: {
225e7481f6eSStanislav Gatev       auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
226e7481f6eSStanislav Gatev       if (SubExprVal == nullptr)
2277d941d6dSStanislav Gatev         break;
228e7481f6eSStanislav Gatev 
229e7481f6eSStanislav Gatev       auto &ExprLoc = Env.createStorageLocation(*S);
230e7481f6eSStanislav Gatev       Env.setStorageLocation(*S, ExprLoc);
231e7481f6eSStanislav Gatev       Env.setValue(ExprLoc, *SubExprVal);
2327d941d6dSStanislav Gatev       break;
233e7481f6eSStanislav Gatev     }
234d002495bSYitzhak Mandelbaum 
235d002495bSYitzhak Mandelbaum     case CK_IntegralCast:
236d002495bSYitzhak Mandelbaum       // FIXME: This cast creates a new integral value from the
237d002495bSYitzhak Mandelbaum       // subexpression. But, because we don't model integers, we don't
238d002495bSYitzhak Mandelbaum       // distinguish between this new value and the underlying one. If integer
239d002495bSYitzhak Mandelbaum       // modeling is added, then update this code to create a fresh location and
240d002495bSYitzhak Mandelbaum       // value.
241092a530cSStanislav Gatev     case CK_UncheckedDerivedToBase:
242092a530cSStanislav Gatev     case CK_ConstructorConversion:
243092a530cSStanislav Gatev     case CK_UserDefinedConversion:
244092a530cSStanislav Gatev       // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
245092a530cSStanislav Gatev       // CK_ConstructorConversion, and CK_UserDefinedConversion.
2467d941d6dSStanislav Gatev     case CK_NoOp: {
2477d941d6dSStanislav Gatev       // FIXME: Consider making `Environment::getStorageLocation` skip noop
2487d941d6dSStanislav Gatev       // expressions (this and other similar expressions in the file) instead of
2497d941d6dSStanislav Gatev       // assigning them storage locations.
2507d941d6dSStanislav Gatev       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
2517d941d6dSStanislav Gatev       if (SubExprLoc == nullptr)
2527d941d6dSStanislav Gatev         break;
2537d941d6dSStanislav Gatev 
2547d941d6dSStanislav Gatev       Env.setStorageLocation(*S, *SubExprLoc);
2557d941d6dSStanislav Gatev       break;
2567d941d6dSStanislav Gatev     }
257b611376eSWei Yi Tee     case CK_NullToPointer:
258b611376eSWei Yi Tee     case CK_NullToMemberPointer: {
259b611376eSWei Yi Tee       auto &Loc = Env.createStorageLocation(S->getType());
260b611376eSWei Yi Tee       Env.setStorageLocation(*S, Loc);
261b611376eSWei Yi Tee 
262b611376eSWei Yi Tee       auto &NullPointerVal =
263b611376eSWei Yi Tee           Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
264b611376eSWei Yi Tee       Env.setValue(Loc, NullPointerVal);
265b611376eSWei Yi Tee       break;
266b611376eSWei Yi Tee     }
2677d941d6dSStanislav Gatev     default:
2687d941d6dSStanislav Gatev       break;
2697d941d6dSStanislav Gatev     }
270e7481f6eSStanislav Gatev   }
271e7481f6eSStanislav Gatev 
VisitUnaryOperator(const UnaryOperator * S)272e7481f6eSStanislav Gatev   void VisitUnaryOperator(const UnaryOperator *S) {
27362b2a47aSEric Li     const Expr *SubExpr = S->getSubExpr();
27459e031ffSStanislav Gatev     assert(SubExpr != nullptr);
27559e031ffSStanislav Gatev 
27659e031ffSStanislav Gatev     switch (S->getOpcode()) {
27759e031ffSStanislav Gatev     case UO_Deref: {
278acd4b035SStanislav Gatev       // Skip past a reference to handle dereference of a dependent pointer.
279e7481f6eSStanislav Gatev       const auto *SubExprVal = cast_or_null<PointerValue>(
28059e031ffSStanislav Gatev           Env.getValue(*SubExpr, SkipPast::Reference));
281e7481f6eSStanislav Gatev       if (SubExprVal == nullptr)
28259e031ffSStanislav Gatev         break;
283e7481f6eSStanislav Gatev 
284e7481f6eSStanislav Gatev       auto &Loc = Env.createStorageLocation(*S);
285e7481f6eSStanislav Gatev       Env.setStorageLocation(*S, Loc);
286e7481f6eSStanislav Gatev       Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
287e7481f6eSStanislav Gatev                             SubExprVal->getPointeeLoc())));
28859e031ffSStanislav Gatev       break;
289e7481f6eSStanislav Gatev     }
29059e031ffSStanislav Gatev     case UO_AddrOf: {
29159e031ffSStanislav Gatev       // Do not form a pointer to a reference. If `SubExpr` is assigned a
29259e031ffSStanislav Gatev       // `ReferenceValue` then form a value that points to the location of its
29359e031ffSStanislav Gatev       // pointee.
29459e031ffSStanislav Gatev       StorageLocation *PointeeLoc =
29559e031ffSStanislav Gatev           Env.getStorageLocation(*SubExpr, SkipPast::Reference);
29659e031ffSStanislav Gatev       if (PointeeLoc == nullptr)
29759e031ffSStanislav Gatev         break;
29859e031ffSStanislav Gatev 
29959e031ffSStanislav Gatev       auto &PointerLoc = Env.createStorageLocation(*S);
30059e031ffSStanislav Gatev       auto &PointerVal =
30159e031ffSStanislav Gatev           Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
30259e031ffSStanislav Gatev       Env.setStorageLocation(*S, PointerLoc);
30359e031ffSStanislav Gatev       Env.setValue(PointerLoc, PointerVal);
30459e031ffSStanislav Gatev       break;
30559e031ffSStanislav Gatev     }
306dd4dde8dSStanislav Gatev     case UO_LNot: {
307dd4dde8dSStanislav Gatev       auto *SubExprVal =
308dd4dde8dSStanislav Gatev           dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None));
309dd4dde8dSStanislav Gatev       if (SubExprVal == nullptr)
310a4808415SStanislav Gatev         break;
311dd4dde8dSStanislav Gatev 
312dd4dde8dSStanislav Gatev       auto &ExprLoc = Env.createStorageLocation(*S);
313dd4dde8dSStanislav Gatev       Env.setStorageLocation(*S, ExprLoc);
3141e571585SStanislav Gatev       Env.setValue(ExprLoc, Env.makeNot(*SubExprVal));
315a4808415SStanislav Gatev       break;
316dd4dde8dSStanislav Gatev     }
31759e031ffSStanislav Gatev     default:
31859e031ffSStanislav Gatev       break;
31959e031ffSStanislav Gatev     }
320e7481f6eSStanislav Gatev   }
321e7481f6eSStanislav Gatev 
VisitCXXThisExpr(const CXXThisExpr * S)32299f7d55eSStanislav Gatev   void VisitCXXThisExpr(const CXXThisExpr *S) {
32399f7d55eSStanislav Gatev     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
32433b598a8SEric Li     if (ThisPointeeLoc == nullptr)
32533b598a8SEric Li       // Unions are not supported yet, and will not have a location for the
32633b598a8SEric Li       // `this` expression's pointee.
32733b598a8SEric Li       return;
32899f7d55eSStanislav Gatev 
32999f7d55eSStanislav Gatev     auto &Loc = Env.createStorageLocation(*S);
33099f7d55eSStanislav Gatev     Env.setStorageLocation(*S, Loc);
33199f7d55eSStanislav Gatev     Env.setValue(Loc, Env.takeOwnership(
33299f7d55eSStanislav Gatev                           std::make_unique<PointerValue>(*ThisPointeeLoc)));
33399f7d55eSStanislav Gatev   }
33499f7d55eSStanislav Gatev 
VisitMemberExpr(const MemberExpr * S)33599f7d55eSStanislav Gatev   void VisitMemberExpr(const MemberExpr *S) {
33699f7d55eSStanislav Gatev     ValueDecl *Member = S->getMemberDecl();
33799f7d55eSStanislav Gatev     assert(Member != nullptr);
33899f7d55eSStanislav Gatev 
33999f7d55eSStanislav Gatev     // FIXME: Consider assigning pointer values to function member expressions.
34099f7d55eSStanislav Gatev     if (Member->isFunctionOrFunctionTemplate())
34199f7d55eSStanislav Gatev       return;
34299f7d55eSStanislav Gatev 
34303dff121SStanislav Gatev     if (auto *D = dyn_cast<VarDecl>(Member)) {
34403dff121SStanislav Gatev       if (D->hasGlobalStorage()) {
34503dff121SStanislav Gatev         auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None);
34603dff121SStanislav Gatev         if (VarDeclLoc == nullptr)
34703dff121SStanislav Gatev           return;
34803dff121SStanislav Gatev 
34903dff121SStanislav Gatev         if (VarDeclLoc->getType()->isReferenceType()) {
35003dff121SStanislav Gatev           Env.setStorageLocation(*S, *VarDeclLoc);
35103dff121SStanislav Gatev         } else {
35203dff121SStanislav Gatev           auto &Loc = Env.createStorageLocation(*S);
35303dff121SStanislav Gatev           Env.setStorageLocation(*S, Loc);
35403dff121SStanislav Gatev           Env.setValue(Loc, Env.takeOwnership(
35503dff121SStanislav Gatev                                 std::make_unique<ReferenceValue>(*VarDeclLoc)));
35603dff121SStanislav Gatev         }
35703dff121SStanislav Gatev         return;
35803dff121SStanislav Gatev       }
35903dff121SStanislav Gatev     }
36003dff121SStanislav Gatev 
36199f7d55eSStanislav Gatev     // The receiver can be either a value or a pointer to a value. Skip past the
36299f7d55eSStanislav Gatev     // indirection to handle both cases.
36399f7d55eSStanislav Gatev     auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
36499f7d55eSStanislav Gatev         Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
36599f7d55eSStanislav Gatev     if (BaseLoc == nullptr)
36699f7d55eSStanislav Gatev       return;
36799f7d55eSStanislav Gatev 
36899f7d55eSStanislav Gatev     // FIXME: Add support for union types.
36999f7d55eSStanislav Gatev     if (BaseLoc->getType()->isUnionType())
37099f7d55eSStanislav Gatev       return;
37199f7d55eSStanislav Gatev 
37299f7d55eSStanislav Gatev     auto &MemberLoc = BaseLoc->getChild(*Member);
37399f7d55eSStanislav Gatev     if (MemberLoc.getType()->isReferenceType()) {
37499f7d55eSStanislav Gatev       Env.setStorageLocation(*S, MemberLoc);
37599f7d55eSStanislav Gatev     } else {
37699f7d55eSStanislav Gatev       auto &Loc = Env.createStorageLocation(*S);
37799f7d55eSStanislav Gatev       Env.setStorageLocation(*S, Loc);
37899f7d55eSStanislav Gatev       Env.setValue(
37999f7d55eSStanislav Gatev           Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
38099f7d55eSStanislav Gatev     }
38199f7d55eSStanislav Gatev   }
38299f7d55eSStanislav Gatev 
VisitCXXDefaultInitExpr(const CXXDefaultInitExpr * S)383963f4005SStanislav Gatev   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
384963f4005SStanislav Gatev     const Expr *InitExpr = S->getExpr();
385963f4005SStanislav Gatev     assert(InitExpr != nullptr);
386963f4005SStanislav Gatev 
387963f4005SStanislav Gatev     Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
388963f4005SStanislav Gatev     if (InitExprVal == nullptr)
389963f4005SStanislav Gatev       return;
390963f4005SStanislav Gatev 
391963f4005SStanislav Gatev     const FieldDecl *Field = S->getField();
392963f4005SStanislav Gatev     assert(Field != nullptr);
393963f4005SStanislav Gatev 
394963f4005SStanislav Gatev     auto &ThisLoc =
395963f4005SStanislav Gatev         *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
396963f4005SStanislav Gatev     auto &FieldLoc = ThisLoc.getChild(*Field);
397963f4005SStanislav Gatev     Env.setValue(FieldLoc, *InitExprVal);
398963f4005SStanislav Gatev   }
399963f4005SStanislav Gatev 
VisitCXXConstructExpr(const CXXConstructExpr * S)4007d941d6dSStanislav Gatev   void VisitCXXConstructExpr(const CXXConstructExpr *S) {
4017d941d6dSStanislav Gatev     const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
4027d941d6dSStanislav Gatev     assert(ConstructorDecl != nullptr);
4037d941d6dSStanislav Gatev 
4047d941d6dSStanislav Gatev     if (ConstructorDecl->isCopyOrMoveConstructor()) {
4057d941d6dSStanislav Gatev       assert(S->getNumArgs() == 1);
4067d941d6dSStanislav Gatev 
4077d941d6dSStanislav Gatev       const Expr *Arg = S->getArg(0);
4087d941d6dSStanislav Gatev       assert(Arg != nullptr);
4097d941d6dSStanislav Gatev 
4107d941d6dSStanislav Gatev       if (S->isElidable()) {
4117d941d6dSStanislav Gatev         auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
4127d941d6dSStanislav Gatev         if (ArgLoc == nullptr)
4137d941d6dSStanislav Gatev           return;
4147d941d6dSStanislav Gatev 
4157d941d6dSStanislav Gatev         Env.setStorageLocation(*S, *ArgLoc);
4167d941d6dSStanislav Gatev       } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) {
4177d941d6dSStanislav Gatev         auto &Loc = Env.createStorageLocation(*S);
4187d941d6dSStanislav Gatev         Env.setStorageLocation(*S, Loc);
4197d941d6dSStanislav Gatev         Env.setValue(Loc, *ArgVal);
4207d941d6dSStanislav Gatev       }
4217d941d6dSStanislav Gatev       return;
4227d941d6dSStanislav Gatev     }
4237d941d6dSStanislav Gatev 
4247d941d6dSStanislav Gatev     auto &Loc = Env.createStorageLocation(*S);
4257d941d6dSStanislav Gatev     Env.setStorageLocation(*S, Loc);
426782eced5SStanislav Gatev     if (Value *Val = Env.createValue(S->getType()))
427782eced5SStanislav Gatev       Env.setValue(Loc, *Val);
4287d941d6dSStanislav Gatev   }
4297d941d6dSStanislav Gatev 
VisitCXXOperatorCallExpr(const CXXOperatorCallExpr * S)4307d941d6dSStanislav Gatev   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
4317d941d6dSStanislav Gatev     if (S->getOperator() == OO_Equal) {
4327d941d6dSStanislav Gatev       assert(S->getNumArgs() == 2);
4337d941d6dSStanislav Gatev 
4347d941d6dSStanislav Gatev       const Expr *Arg0 = S->getArg(0);
4357d941d6dSStanislav Gatev       assert(Arg0 != nullptr);
4367d941d6dSStanislav Gatev 
4377d941d6dSStanislav Gatev       const Expr *Arg1 = S->getArg(1);
4387d941d6dSStanislav Gatev       assert(Arg1 != nullptr);
4397d941d6dSStanislav Gatev 
4407d941d6dSStanislav Gatev       // Evaluate only copy and move assignment operators.
4417d941d6dSStanislav Gatev       auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
4427d941d6dSStanislav Gatev       auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
4437d941d6dSStanislav Gatev       if (Arg0Type != Arg1Type)
4447d941d6dSStanislav Gatev         return;
4457d941d6dSStanislav Gatev 
4467d941d6dSStanislav Gatev       auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);
4477d941d6dSStanislav Gatev       if (ObjectLoc == nullptr)
4487d941d6dSStanislav Gatev         return;
4497d941d6dSStanislav Gatev 
4507d941d6dSStanislav Gatev       auto *Val = Env.getValue(*Arg1, SkipPast::Reference);
4517d941d6dSStanislav Gatev       if (Val == nullptr)
4527d941d6dSStanislav Gatev         return;
4537d941d6dSStanislav Gatev 
454b000b770SStanislav Gatev       // Assign a value to the storage location of the object.
4557d941d6dSStanislav Gatev       Env.setValue(*ObjectLoc, *Val);
456b000b770SStanislav Gatev 
457b000b770SStanislav Gatev       // FIXME: Add a test for the value of the whole expression.
458b000b770SStanislav Gatev       // Assign a storage location for the whole expression.
459b000b770SStanislav Gatev       Env.setStorageLocation(*S, *ObjectLoc);
4607d941d6dSStanislav Gatev     }
4617d941d6dSStanislav Gatev   }
4627d941d6dSStanislav Gatev 
VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr * S)4637d941d6dSStanislav Gatev   void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
4647d941d6dSStanislav Gatev     if (S->getCastKind() == CK_ConstructorConversion) {
4657d941d6dSStanislav Gatev       const Expr *SubExpr = S->getSubExpr();
4667d941d6dSStanislav Gatev       assert(SubExpr != nullptr);
4677d941d6dSStanislav Gatev 
4687d941d6dSStanislav Gatev       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
4697d941d6dSStanislav Gatev       if (SubExprLoc == nullptr)
4707d941d6dSStanislav Gatev         return;
4717d941d6dSStanislav Gatev 
4727d941d6dSStanislav Gatev       Env.setStorageLocation(*S, *SubExprLoc);
4737d941d6dSStanislav Gatev     }
4747d941d6dSStanislav Gatev   }
4757d941d6dSStanislav Gatev 
VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr * S)4767d941d6dSStanislav Gatev   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
4777d941d6dSStanislav Gatev     auto &Loc = Env.createStorageLocation(*S);
4787d941d6dSStanislav Gatev     Env.setStorageLocation(*S, Loc);
479782eced5SStanislav Gatev     if (Value *Val = Env.createValue(S->getType()))
480782eced5SStanislav Gatev       Env.setValue(Loc, *Val);
4817d941d6dSStanislav Gatev   }
4827d941d6dSStanislav Gatev 
VisitCallExpr(const CallExpr * S)4837d941d6dSStanislav Gatev   void VisitCallExpr(const CallExpr *S) {
484506ec85bSYitzhak Mandelbaum     // Of clang's builtins, only `__builtin_expect` is handled explicitly, since
485506ec85bSYitzhak Mandelbaum     // others (like trap, debugtrap, and unreachable) are handled by CFG
486506ec85bSYitzhak Mandelbaum     // construction.
4877d941d6dSStanislav Gatev     if (S->isCallToStdMove()) {
4887d941d6dSStanislav Gatev       assert(S->getNumArgs() == 1);
4897d941d6dSStanislav Gatev 
4907d941d6dSStanislav Gatev       const Expr *Arg = S->getArg(0);
4917d941d6dSStanislav Gatev       assert(Arg != nullptr);
4927d941d6dSStanislav Gatev 
4937d941d6dSStanislav Gatev       auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
4947d941d6dSStanislav Gatev       if (ArgLoc == nullptr)
4957d941d6dSStanislav Gatev         return;
4967d941d6dSStanislav Gatev 
4977d941d6dSStanislav Gatev       Env.setStorageLocation(*S, *ArgLoc);
498506ec85bSYitzhak Mandelbaum     } else if (S->getDirectCallee() != nullptr &&
499506ec85bSYitzhak Mandelbaum                S->getDirectCallee()->getBuiltinID() ==
500506ec85bSYitzhak Mandelbaum                    Builtin::BI__builtin_expect) {
501506ec85bSYitzhak Mandelbaum       assert(S->getNumArgs() > 0);
502506ec85bSYitzhak Mandelbaum       assert(S->getArg(0) != nullptr);
503506ec85bSYitzhak Mandelbaum       // `__builtin_expect` returns by-value, so strip away any potential
504506ec85bSYitzhak Mandelbaum       // references in the argument.
50545643cfcSEric Li       auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference);
506506ec85bSYitzhak Mandelbaum       if (ArgLoc == nullptr)
507506ec85bSYitzhak Mandelbaum         return;
508506ec85bSYitzhak Mandelbaum       Env.setStorageLocation(*S, *ArgLoc);
509*300fbf56SSam Estep     } else if (const FunctionDecl *F = S->getDirectCallee()) {
510*300fbf56SSam Estep       // This case is for context-sensitive analysis, which we only do if we
511*300fbf56SSam Estep       // have the callee body available in the translation unit.
512*300fbf56SSam Estep       if (!Options.ContextSensitive || F->getBody() == nullptr)
513*300fbf56SSam Estep         return;
514*300fbf56SSam Estep 
515*300fbf56SSam Estep       auto &ASTCtx = F->getASTContext();
516*300fbf56SSam Estep 
517*300fbf56SSam Estep       // FIXME: Cache these CFGs.
518*300fbf56SSam Estep       auto CFCtx = ControlFlowContext::build(F, F->getBody(), &ASTCtx);
519*300fbf56SSam Estep       // FIXME: Handle errors here and below.
520*300fbf56SSam Estep       assert(CFCtx);
521*300fbf56SSam Estep       auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
522*300fbf56SSam Estep 
523*300fbf56SSam Estep       auto CalleeEnv = Env.pushCall(S);
524*300fbf56SSam Estep 
525*300fbf56SSam Estep       // FIXME: Use the same analysis as the caller for the callee.
526*300fbf56SSam Estep       DataflowAnalysisOptions Options;
527*300fbf56SSam Estep       auto Analysis = NoopAnalysis(ASTCtx, Options);
528*300fbf56SSam Estep 
529*300fbf56SSam Estep       auto BlockToOutputState =
530*300fbf56SSam Estep           dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
531*300fbf56SSam Estep       assert(BlockToOutputState);
532*300fbf56SSam Estep       assert(ExitBlock < BlockToOutputState->size());
533*300fbf56SSam Estep 
534*300fbf56SSam Estep       auto ExitState = (*BlockToOutputState)[ExitBlock];
535*300fbf56SSam Estep       assert(ExitState);
536*300fbf56SSam Estep 
537*300fbf56SSam Estep       Env = ExitState->Env;
5387d941d6dSStanislav Gatev     }
5397d941d6dSStanislav Gatev   }
5407d941d6dSStanislav Gatev 
VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr * S)5417d941d6dSStanislav Gatev   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
5427d941d6dSStanislav Gatev     const Expr *SubExpr = S->getSubExpr();
5437d941d6dSStanislav Gatev     assert(SubExpr != nullptr);
5447d941d6dSStanislav Gatev 
5457d941d6dSStanislav Gatev     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
5467d941d6dSStanislav Gatev     if (SubExprLoc == nullptr)
5477d941d6dSStanislav Gatev       return;
5487d941d6dSStanislav Gatev 
5497d941d6dSStanislav Gatev     Env.setStorageLocation(*S, *SubExprLoc);
5507d941d6dSStanislav Gatev   }
5517d941d6dSStanislav Gatev 
VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr * S)55237e6496cSStanislav Gatev   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
55337e6496cSStanislav Gatev     const Expr *SubExpr = S->getSubExpr();
55437e6496cSStanislav Gatev     assert(SubExpr != nullptr);
55537e6496cSStanislav Gatev 
55637e6496cSStanislav Gatev     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
55737e6496cSStanislav Gatev     if (SubExprLoc == nullptr)
55837e6496cSStanislav Gatev       return;
55937e6496cSStanislav Gatev 
56037e6496cSStanislav Gatev     Env.setStorageLocation(*S, *SubExprLoc);
56137e6496cSStanislav Gatev   }
56237e6496cSStanislav Gatev 
VisitCXXStaticCastExpr(const CXXStaticCastExpr * S)56337e6496cSStanislav Gatev   void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
56437e6496cSStanislav Gatev     if (S->getCastKind() == CK_NoOp) {
56537e6496cSStanislav Gatev       const Expr *SubExpr = S->getSubExpr();
56637e6496cSStanislav Gatev       assert(SubExpr != nullptr);
56737e6496cSStanislav Gatev 
56837e6496cSStanislav Gatev       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
56937e6496cSStanislav Gatev       if (SubExprLoc == nullptr)
57037e6496cSStanislav Gatev         return;
57137e6496cSStanislav Gatev 
57237e6496cSStanislav Gatev       Env.setStorageLocation(*S, *SubExprLoc);
57337e6496cSStanislav Gatev     }
57437e6496cSStanislav Gatev   }
57537e6496cSStanislav Gatev 
VisitConditionalOperator(const ConditionalOperator * S)5768e53ae3dSStanislav Gatev   void VisitConditionalOperator(const ConditionalOperator *S) {
5778e53ae3dSStanislav Gatev     // FIXME: Revisit this once flow conditions are added to the framework. For
5788e53ae3dSStanislav Gatev     // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
5798e53ae3dSStanislav Gatev     // condition.
5808e53ae3dSStanislav Gatev     auto &Loc = Env.createStorageLocation(*S);
5818e53ae3dSStanislav Gatev     Env.setStorageLocation(*S, Loc);
5828e53ae3dSStanislav Gatev     if (Value *Val = Env.createValue(S->getType()))
5838e53ae3dSStanislav Gatev       Env.setValue(Loc, *Val);
5848e53ae3dSStanislav Gatev   }
5858e53ae3dSStanislav Gatev 
VisitInitListExpr(const InitListExpr * S)58664ba462bSStanislav Gatev   void VisitInitListExpr(const InitListExpr *S) {
58764ba462bSStanislav Gatev     QualType Type = S->getType();
58864ba462bSStanislav Gatev 
58964ba462bSStanislav Gatev     auto &Loc = Env.createStorageLocation(*S);
59064ba462bSStanislav Gatev     Env.setStorageLocation(*S, Loc);
59164ba462bSStanislav Gatev 
59264ba462bSStanislav Gatev     auto *Val = Env.createValue(Type);
59364ba462bSStanislav Gatev     if (Val == nullptr)
59464ba462bSStanislav Gatev       return;
59564ba462bSStanislav Gatev 
59664ba462bSStanislav Gatev     Env.setValue(Loc, *Val);
59764ba462bSStanislav Gatev 
59864ba462bSStanislav Gatev     if (Type->isStructureOrClassType()) {
599c0c9d717SDmitri Gribenko       for (auto It : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
600c0c9d717SDmitri Gribenko         const FieldDecl *Field = std::get<0>(It);
60164ba462bSStanislav Gatev         assert(Field != nullptr);
60264ba462bSStanislav Gatev 
603c0c9d717SDmitri Gribenko         const Expr *Init = std::get<1>(It);
60464ba462bSStanislav Gatev         assert(Init != nullptr);
60564ba462bSStanislav Gatev 
60664ba462bSStanislav Gatev         if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
60764ba462bSStanislav Gatev           cast<StructValue>(Val)->setChild(*Field, *InitVal);
60864ba462bSStanislav Gatev       }
60964ba462bSStanislav Gatev     }
61064ba462bSStanislav Gatev     // FIXME: Implement array initialization.
61164ba462bSStanislav Gatev   }
61264ba462bSStanislav Gatev 
VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr * S)61375c22b38SStanislav Gatev   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
61475c22b38SStanislav Gatev     auto &Loc = Env.createStorageLocation(*S);
61575c22b38SStanislav Gatev     Env.setStorageLocation(*S, Loc);
61675c22b38SStanislav Gatev     Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue()));
61775c22b38SStanislav Gatev   }
618af7bc39bSStanislav Gatev 
VisitParenExpr(const ParenExpr * S)61945643cfcSEric Li   void VisitParenExpr(const ParenExpr *S) {
62045643cfcSEric Li     // The CFG does not contain `ParenExpr` as top-level statements in basic
62145643cfcSEric Li     // blocks, however manual traversal to sub-expressions may encounter them.
62245643cfcSEric Li     // Redirect to the sub-expression.
62345643cfcSEric Li     auto *SubExpr = S->getSubExpr();
62445643cfcSEric Li     assert(SubExpr != nullptr);
62545643cfcSEric Li     Visit(SubExpr);
62645643cfcSEric Li   }
62745643cfcSEric Li 
VisitExprWithCleanups(const ExprWithCleanups * S)62845643cfcSEric Li   void VisitExprWithCleanups(const ExprWithCleanups *S) {
62945643cfcSEric Li     // The CFG does not contain `ExprWithCleanups` as top-level statements in
63045643cfcSEric Li     // basic blocks, however manual traversal to sub-expressions may encounter
63145643cfcSEric Li     // them. Redirect to the sub-expression.
63245643cfcSEric Li     auto *SubExpr = S->getSubExpr();
63345643cfcSEric Li     assert(SubExpr != nullptr);
63445643cfcSEric Li     Visit(SubExpr);
63545643cfcSEric Li   }
63645643cfcSEric Li 
637af7bc39bSStanislav Gatev private:
getLogicOperatorSubExprValue(const Expr & SubExpr)638cf63e9d4SStanislav Gatev   BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
639cf63e9d4SStanislav Gatev     // `SubExpr` and its parent logic operator might be part of different basic
640cf63e9d4SStanislav Gatev     // blocks. We try to access the value that is assigned to `SubExpr` in the
641cf63e9d4SStanislav Gatev     // corresponding environment.
642cf63e9d4SStanislav Gatev     if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) {
643cf63e9d4SStanislav Gatev       if (auto *Val = dyn_cast_or_null<BoolValue>(
644cf63e9d4SStanislav Gatev               SubExprEnv->getValue(SubExpr, SkipPast::Reference)))
645cf63e9d4SStanislav Gatev         return *Val;
646cf63e9d4SStanislav Gatev     }
647cf63e9d4SStanislav Gatev 
6485bbef2e3SEric Li     if (Env.getStorageLocation(SubExpr, SkipPast::None) == nullptr) {
649cf63e9d4SStanislav Gatev       // Sub-expressions that are logic operators are not added in basic blocks
650cf63e9d4SStanislav Gatev       // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic
6515bbef2e3SEric Li       // operator, it may not have been evaluated and assigned a value yet. In
6525bbef2e3SEric Li       // that case, we need to first visit `SubExpr` and then try to get the
6535bbef2e3SEric Li       // value that gets assigned to it.
654cf63e9d4SStanislav Gatev       Visit(&SubExpr);
6555bbef2e3SEric Li     }
6565bbef2e3SEric Li 
657cf63e9d4SStanislav Gatev     if (auto *Val = dyn_cast_or_null<BoolValue>(
658cf63e9d4SStanislav Gatev             Env.getValue(SubExpr, SkipPast::Reference)))
659cf63e9d4SStanislav Gatev       return *Val;
660cf63e9d4SStanislav Gatev 
661cf63e9d4SStanislav Gatev     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
662cf63e9d4SStanislav Gatev     // boolean value for it.
663cf63e9d4SStanislav Gatev     return Env.makeAtomicBoolValue();
664cf63e9d4SStanislav Gatev   }
665cf63e9d4SStanislav Gatev 
666dd4dde8dSStanislav Gatev   const StmtToEnvMap &StmtToEnv;
667af7bc39bSStanislav Gatev   Environment &Env;
668*300fbf56SSam Estep   TransferOptions Options;
669af7bc39bSStanislav Gatev };
670af7bc39bSStanislav Gatev 
transfer(const StmtToEnvMap & StmtToEnv,const Stmt & S,Environment & Env,TransferOptions Options)671*300fbf56SSam Estep void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
672*300fbf56SSam Estep               TransferOptions Options) {
673*300fbf56SSam Estep   TransferVisitor(StmtToEnv, Env, Options).Visit(&S);
674af7bc39bSStanislav Gatev }
675af7bc39bSStanislav Gatev 
676af7bc39bSStanislav Gatev } // namespace dataflow
677af7bc39bSStanislav Gatev } // namespace clang
678