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