xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
104eeddc0SDimitry Andric //===-- Transfer.cpp --------------------------------------------*- C++ -*-===//
204eeddc0SDimitry Andric //
304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
604eeddc0SDimitry Andric //
704eeddc0SDimitry Andric //===----------------------------------------------------------------------===//
804eeddc0SDimitry Andric //
904eeddc0SDimitry Andric //  This file defines transfer functions that evaluate program statements and
1004eeddc0SDimitry Andric //  update an environment accordingly.
1104eeddc0SDimitry Andric //
1204eeddc0SDimitry Andric //===----------------------------------------------------------------------===//
1304eeddc0SDimitry Andric 
1404eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Transfer.h"
1504eeddc0SDimitry Andric #include "clang/AST/Decl.h"
1604eeddc0SDimitry Andric #include "clang/AST/DeclBase.h"
1704eeddc0SDimitry Andric #include "clang/AST/DeclCXX.h"
1804eeddc0SDimitry Andric #include "clang/AST/Expr.h"
1904eeddc0SDimitry Andric #include "clang/AST/ExprCXX.h"
2004eeddc0SDimitry Andric #include "clang/AST/OperationKinds.h"
2104eeddc0SDimitry Andric #include "clang/AST/Stmt.h"
2204eeddc0SDimitry Andric #include "clang/AST/StmtVisitor.h"
23972a253aSDimitry Andric #include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
2404eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
25972a253aSDimitry Andric #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
26*06c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/RecordOps.h"
2781ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h"
2881ad6265SDimitry Andric #include "clang/Basic/Builtins.h"
2904eeddc0SDimitry Andric #include "clang/Basic/OperatorKinds.h"
3004eeddc0SDimitry Andric #include "llvm/ADT/STLExtras.h"
3104eeddc0SDimitry Andric #include "llvm/Support/Casting.h"
32bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h"
3304eeddc0SDimitry Andric #include <cassert>
3404eeddc0SDimitry Andric #include <memory>
3504eeddc0SDimitry Andric #include <tuple>
3604eeddc0SDimitry Andric 
3704eeddc0SDimitry Andric namespace clang {
3804eeddc0SDimitry Andric namespace dataflow {
3904eeddc0SDimitry Andric 
40*06c3fb27SDimitry Andric const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const {
41*06c3fb27SDimitry Andric   auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
42*06c3fb27SDimitry Andric   assert(BlockIt != CFCtx.getStmtToBlock().end());
43*06c3fb27SDimitry Andric   if (!CFCtx.isBlockReachable(*BlockIt->getSecond()))
44*06c3fb27SDimitry Andric     return nullptr;
45*06c3fb27SDimitry Andric   const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
46*06c3fb27SDimitry Andric   assert(State);
47*06c3fb27SDimitry Andric   return &State->Env;
4804eeddc0SDimitry Andric }
4904eeddc0SDimitry Andric 
50*06c3fb27SDimitry Andric static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
51*06c3fb27SDimitry Andric                                           Environment &Env) {
52*06c3fb27SDimitry Andric   Value *LHSValue = Env.getValueStrict(LHS);
53*06c3fb27SDimitry Andric   Value *RHSValue = Env.getValueStrict(RHS);
54bdd1243dSDimitry Andric 
55*06c3fb27SDimitry Andric   if (LHSValue == RHSValue)
56*06c3fb27SDimitry Andric     return Env.getBoolLiteralValue(true);
57bdd1243dSDimitry Andric 
58*06c3fb27SDimitry Andric   if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue))
59*06c3fb27SDimitry Andric     if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue))
60*06c3fb27SDimitry Andric       return Env.makeIff(*LHSBool, *RHSBool);
61bdd1243dSDimitry Andric 
62*06c3fb27SDimitry Andric   return Env.makeAtomicBoolValue();
63bdd1243dSDimitry Andric }
64bdd1243dSDimitry Andric 
65bdd1243dSDimitry Andric static BoolValue &unpackValue(BoolValue &V, Environment &Env) {
66*06c3fb27SDimitry Andric   if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) {
67*06c3fb27SDimitry Andric     auto &A = Env.getDataflowAnalysisContext().arena();
68*06c3fb27SDimitry Andric     return A.makeBoolValue(A.makeAtomRef(Top->getAtom()));
69bdd1243dSDimitry Andric   }
70*06c3fb27SDimitry Andric   return V;
71bdd1243dSDimitry Andric }
72bdd1243dSDimitry Andric 
73bdd1243dSDimitry Andric // Unpacks the value (if any) associated with `E` and updates `E` to the new
74*06c3fb27SDimitry Andric // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion,
75*06c3fb27SDimitry Andric // by skipping past the reference.
76bdd1243dSDimitry Andric static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) {
77*06c3fb27SDimitry Andric   auto *Loc = Env.getStorageLocationStrict(E);
78bdd1243dSDimitry Andric   if (Loc == nullptr)
79bdd1243dSDimitry Andric     return nullptr;
80bdd1243dSDimitry Andric   auto *Val = Env.getValue(*Loc);
81bdd1243dSDimitry Andric 
82bdd1243dSDimitry Andric   auto *B = dyn_cast_or_null<BoolValue>(Val);
83bdd1243dSDimitry Andric   if (B == nullptr)
84bdd1243dSDimitry Andric     return Val;
85bdd1243dSDimitry Andric 
86bdd1243dSDimitry Andric   auto &UnpackedVal = unpackValue(*B, Env);
87bdd1243dSDimitry Andric   if (&UnpackedVal == Val)
88bdd1243dSDimitry Andric     return Val;
89bdd1243dSDimitry Andric   Env.setValue(*Loc, UnpackedVal);
90bdd1243dSDimitry Andric   return &UnpackedVal;
91bdd1243dSDimitry Andric }
92bdd1243dSDimitry Andric 
93*06c3fb27SDimitry Andric static void propagateValue(const Expr &From, const Expr &To, Environment &Env) {
94*06c3fb27SDimitry Andric   if (auto *Val = Env.getValueStrict(From))
95*06c3fb27SDimitry Andric     Env.setValueStrict(To, *Val);
96*06c3fb27SDimitry Andric }
97*06c3fb27SDimitry Andric 
98*06c3fb27SDimitry Andric static void propagateStorageLocation(const Expr &From, const Expr &To,
99*06c3fb27SDimitry Andric                                      Environment &Env) {
100*06c3fb27SDimitry Andric   if (auto *Loc = Env.getStorageLocationStrict(From))
101*06c3fb27SDimitry Andric     Env.setStorageLocationStrict(To, *Loc);
102*06c3fb27SDimitry Andric }
103*06c3fb27SDimitry Andric 
104*06c3fb27SDimitry Andric // Propagates the value or storage location of `From` to `To` in cases where
105*06c3fb27SDimitry Andric // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff
106*06c3fb27SDimitry Andric // `From` is a glvalue.
107*06c3fb27SDimitry Andric static void propagateValueOrStorageLocation(const Expr &From, const Expr &To,
108*06c3fb27SDimitry Andric                                             Environment &Env) {
109*06c3fb27SDimitry Andric   assert(From.isGLValue() == To.isGLValue());
110*06c3fb27SDimitry Andric   if (From.isGLValue())
111*06c3fb27SDimitry Andric     propagateStorageLocation(From, To, Env);
112*06c3fb27SDimitry Andric   else
113*06c3fb27SDimitry Andric     propagateValue(From, To, Env);
114*06c3fb27SDimitry Andric }
115*06c3fb27SDimitry Andric 
116*06c3fb27SDimitry Andric namespace {
117*06c3fb27SDimitry Andric 
11804eeddc0SDimitry Andric class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
11904eeddc0SDimitry Andric public:
120bdd1243dSDimitry Andric   TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
121bdd1243dSDimitry Andric       : StmtToEnv(StmtToEnv), Env(Env) {}
12204eeddc0SDimitry Andric 
12304eeddc0SDimitry Andric   void VisitBinaryOperator(const BinaryOperator *S) {
12481ad6265SDimitry Andric     const Expr *LHS = S->getLHS();
12504eeddc0SDimitry Andric     assert(LHS != nullptr);
12681ad6265SDimitry Andric 
12781ad6265SDimitry Andric     const Expr *RHS = S->getRHS();
12881ad6265SDimitry Andric     assert(RHS != nullptr);
12981ad6265SDimitry Andric 
13081ad6265SDimitry Andric     switch (S->getOpcode()) {
13181ad6265SDimitry Andric     case BO_Assign: {
132*06c3fb27SDimitry Andric       auto *LHSLoc = Env.getStorageLocationStrict(*LHS);
13304eeddc0SDimitry Andric       if (LHSLoc == nullptr)
13481ad6265SDimitry Andric         break;
13504eeddc0SDimitry Andric 
136*06c3fb27SDimitry Andric       auto *RHSVal = Env.getValueStrict(*RHS);
13704eeddc0SDimitry Andric       if (RHSVal == nullptr)
13881ad6265SDimitry Andric         break;
13904eeddc0SDimitry Andric 
14004eeddc0SDimitry Andric       // Assign a value to the storage location of the left-hand side.
14104eeddc0SDimitry Andric       Env.setValue(*LHSLoc, *RHSVal);
14204eeddc0SDimitry Andric 
14304eeddc0SDimitry Andric       // Assign a storage location for the whole expression.
14404eeddc0SDimitry Andric       Env.setStorageLocation(*S, *LHSLoc);
14581ad6265SDimitry Andric       break;
14604eeddc0SDimitry Andric     }
14781ad6265SDimitry Andric     case BO_LAnd:
14881ad6265SDimitry Andric     case BO_LOr: {
149*06c3fb27SDimitry Andric       auto &Loc = Env.createStorageLocation(*S);
150*06c3fb27SDimitry Andric       Env.setStorageLocation(*S, Loc);
151*06c3fb27SDimitry Andric 
15281ad6265SDimitry Andric       BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
15381ad6265SDimitry Andric       BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
15481ad6265SDimitry Andric 
15581ad6265SDimitry Andric       if (S->getOpcode() == BO_LAnd)
15681ad6265SDimitry Andric         Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
15781ad6265SDimitry Andric       else
15881ad6265SDimitry Andric         Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
15981ad6265SDimitry Andric       break;
16081ad6265SDimitry Andric     }
16181ad6265SDimitry Andric     case BO_NE:
16281ad6265SDimitry Andric     case BO_EQ: {
16381ad6265SDimitry Andric       auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
16481ad6265SDimitry Andric       auto &Loc = Env.createStorageLocation(*S);
16581ad6265SDimitry Andric       Env.setStorageLocation(*S, Loc);
16681ad6265SDimitry Andric       Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue
16781ad6265SDimitry Andric                                                 : Env.makeNot(LHSEqRHSValue));
16881ad6265SDimitry Andric       break;
16981ad6265SDimitry Andric     }
17081ad6265SDimitry Andric     case BO_Comma: {
171*06c3fb27SDimitry Andric       propagateValueOrStorageLocation(*RHS, *S, Env);
17281ad6265SDimitry Andric       break;
17381ad6265SDimitry Andric     }
17481ad6265SDimitry Andric     default:
17581ad6265SDimitry Andric       break;
17681ad6265SDimitry Andric     }
17704eeddc0SDimitry Andric   }
17804eeddc0SDimitry Andric 
17904eeddc0SDimitry Andric   void VisitDeclRefExpr(const DeclRefExpr *S) {
180bdd1243dSDimitry Andric     const ValueDecl *VD = S->getDecl();
181bdd1243dSDimitry Andric     assert(VD != nullptr);
182*06c3fb27SDimitry Andric 
183*06c3fb27SDimitry Andric     // `DeclRefExpr`s to fields and non-static methods aren't glvalues, and
184*06c3fb27SDimitry Andric     // there's also no sensible `Value` we can assign to them, so skip them.
185*06c3fb27SDimitry Andric     if (isa<FieldDecl>(VD))
186*06c3fb27SDimitry Andric       return;
187*06c3fb27SDimitry Andric     if (auto *Method = dyn_cast<CXXMethodDecl>(VD);
188*06c3fb27SDimitry Andric         Method && !Method->isStatic())
189*06c3fb27SDimitry Andric       return;
190*06c3fb27SDimitry Andric 
191*06c3fb27SDimitry Andric     auto *DeclLoc = Env.getStorageLocation(*VD);
19204eeddc0SDimitry Andric     if (DeclLoc == nullptr)
19304eeddc0SDimitry Andric       return;
19404eeddc0SDimitry Andric 
195*06c3fb27SDimitry Andric     Env.setStorageLocationStrict(*S, *DeclLoc);
19604eeddc0SDimitry Andric   }
19704eeddc0SDimitry Andric 
19804eeddc0SDimitry Andric   void VisitDeclStmt(const DeclStmt *S) {
19904eeddc0SDimitry Andric     // Group decls are converted into single decls in the CFG so the cast below
20004eeddc0SDimitry Andric     // is safe.
20104eeddc0SDimitry Andric     const auto &D = *cast<VarDecl>(S->getSingleDecl());
20281ad6265SDimitry Andric 
203*06c3fb27SDimitry Andric     ProcessVarDecl(D);
204*06c3fb27SDimitry Andric   }
205*06c3fb27SDimitry Andric 
206*06c3fb27SDimitry Andric   void ProcessVarDecl(const VarDecl &D) {
20781ad6265SDimitry Andric     // Static local vars are already initialized in `Environment`.
20881ad6265SDimitry Andric     if (D.hasGlobalStorage())
20981ad6265SDimitry Andric       return;
21081ad6265SDimitry Andric 
211*06c3fb27SDimitry Andric     // If this is the holding variable for a `BindingDecl`, we may already
212*06c3fb27SDimitry Andric     // have a storage location set up -- so check. (See also explanation below
213*06c3fb27SDimitry Andric     // where we process the `BindingDecl`.)
214*06c3fb27SDimitry Andric     if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr)
21504eeddc0SDimitry Andric       return;
21604eeddc0SDimitry Andric 
217*06c3fb27SDimitry Andric     assert(Env.getStorageLocation(D) == nullptr);
21804eeddc0SDimitry Andric 
219*06c3fb27SDimitry Andric     Env.setStorageLocation(D, Env.createObject(D));
22081ad6265SDimitry Andric 
221*06c3fb27SDimitry Andric     // `DecompositionDecl` must be handled after we've interpreted the loc
222*06c3fb27SDimitry Andric     // itself, because the binding expression refers back to the
223*06c3fb27SDimitry Andric     // `DecompositionDecl` (even though it has no written name).
22481ad6265SDimitry Andric     if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) {
22581ad6265SDimitry Andric       // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This
22681ad6265SDimitry Andric       // needs to be evaluated after initializing the values in the storage for
22781ad6265SDimitry Andric       // VarDecl, as the bindings refer to them.
22881ad6265SDimitry Andric       // FIXME: Add support for ArraySubscriptExpr.
229bdd1243dSDimitry Andric       // FIXME: Consider adding AST nodes used in BindingDecls to the CFG.
23081ad6265SDimitry Andric       for (const auto *B : Decomp->bindings()) {
231bdd1243dSDimitry Andric         if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) {
23281ad6265SDimitry Andric           auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());
23381ad6265SDimitry Andric           if (DE == nullptr)
23481ad6265SDimitry Andric             continue;
23581ad6265SDimitry Andric 
236bdd1243dSDimitry Andric           // ME and its base haven't been visited because they aren't included
237bdd1243dSDimitry Andric           // in the statements of the CFG basic block.
23881ad6265SDimitry Andric           VisitDeclRefExpr(DE);
23981ad6265SDimitry Andric           VisitMemberExpr(ME);
24081ad6265SDimitry Andric 
24181ad6265SDimitry Andric           if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference))
24281ad6265SDimitry Andric             Env.setStorageLocation(*B, *Loc);
243bdd1243dSDimitry Andric         } else if (auto *VD = B->getHoldingVar()) {
244*06c3fb27SDimitry Andric           // Holding vars are used to back the `BindingDecl`s of tuple-like
245*06c3fb27SDimitry Andric           // types. The holding var declarations appear after the
246*06c3fb27SDimitry Andric           // `DecompositionDecl`, so we have to explicitly process them here
247*06c3fb27SDimitry Andric           // to know their storage location. They will be processed a second
248*06c3fb27SDimitry Andric           // time when we visit their `VarDecl`s, so we have code that protects
249*06c3fb27SDimitry Andric           // against this above.
250*06c3fb27SDimitry Andric           ProcessVarDecl(*VD);
251*06c3fb27SDimitry Andric           auto *VDLoc = Env.getStorageLocation(*VD);
252*06c3fb27SDimitry Andric           assert(VDLoc != nullptr);
253*06c3fb27SDimitry Andric           Env.setStorageLocation(*B, *VDLoc);
254bdd1243dSDimitry Andric         }
25581ad6265SDimitry Andric       }
25604eeddc0SDimitry Andric     }
25704eeddc0SDimitry Andric   }
25804eeddc0SDimitry Andric 
25904eeddc0SDimitry Andric   void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
26081ad6265SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
26104eeddc0SDimitry Andric     assert(SubExpr != nullptr);
26204eeddc0SDimitry Andric 
26304eeddc0SDimitry Andric     switch (S->getCastKind()) {
26481ad6265SDimitry Andric     case CK_IntegralToBoolean: {
26581ad6265SDimitry Andric       // This cast creates a new, boolean value from the integral value. We
26681ad6265SDimitry Andric       // model that with a fresh value in the environment, unless it's already a
26781ad6265SDimitry Andric       // boolean.
268*06c3fb27SDimitry Andric       if (auto *SubExprVal =
269*06c3fb27SDimitry Andric               dyn_cast_or_null<BoolValue>(Env.getValueStrict(*SubExpr)))
270*06c3fb27SDimitry Andric         Env.setValueStrict(*S, *SubExprVal);
27181ad6265SDimitry Andric       else
27281ad6265SDimitry Andric         // FIXME: If integer modeling is added, then update this code to create
27381ad6265SDimitry Andric         // the boolean based on the integer model.
274*06c3fb27SDimitry Andric         Env.setValueStrict(*S, Env.makeAtomicBoolValue());
27581ad6265SDimitry Andric       break;
27681ad6265SDimitry Andric     }
27781ad6265SDimitry Andric 
27804eeddc0SDimitry Andric     case CK_LValueToRValue: {
279bdd1243dSDimitry Andric       // When an L-value is used as an R-value, it may result in sharing, so we
280*06c3fb27SDimitry Andric       // need to unpack any nested `Top`s. We also need to strip off the
281*06c3fb27SDimitry Andric       // `ReferenceValue` associated with the lvalue.
282bdd1243dSDimitry Andric       auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env);
28304eeddc0SDimitry Andric       if (SubExprVal == nullptr)
28404eeddc0SDimitry Andric         break;
28504eeddc0SDimitry Andric 
28604eeddc0SDimitry Andric       auto &ExprLoc = Env.createStorageLocation(*S);
28704eeddc0SDimitry Andric       Env.setStorageLocation(*S, ExprLoc);
28804eeddc0SDimitry Andric       Env.setValue(ExprLoc, *SubExprVal);
28904eeddc0SDimitry Andric       break;
29004eeddc0SDimitry Andric     }
29181ad6265SDimitry Andric 
29281ad6265SDimitry Andric     case CK_IntegralCast:
29381ad6265SDimitry Andric       // FIXME: This cast creates a new integral value from the
29481ad6265SDimitry Andric       // subexpression. But, because we don't model integers, we don't
29581ad6265SDimitry Andric       // distinguish between this new value and the underlying one. If integer
29681ad6265SDimitry Andric       // modeling is added, then update this code to create a fresh location and
29781ad6265SDimitry Andric       // value.
29881ad6265SDimitry Andric     case CK_UncheckedDerivedToBase:
29981ad6265SDimitry Andric     case CK_ConstructorConversion:
30081ad6265SDimitry Andric     case CK_UserDefinedConversion:
30181ad6265SDimitry Andric       // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
30281ad6265SDimitry Andric       // CK_ConstructorConversion, and CK_UserDefinedConversion.
30304eeddc0SDimitry Andric     case CK_NoOp: {
30404eeddc0SDimitry Andric       // FIXME: Consider making `Environment::getStorageLocation` skip noop
305*06c3fb27SDimitry Andric       // expressions (this and other similar expressions in the file) instead
306*06c3fb27SDimitry Andric       // of assigning them storage locations.
307*06c3fb27SDimitry Andric       propagateValueOrStorageLocation(*SubExpr, *S, Env);
30804eeddc0SDimitry Andric       break;
30904eeddc0SDimitry Andric     }
310*06c3fb27SDimitry Andric     case CK_NullToPointer: {
31181ad6265SDimitry Andric       auto &Loc = Env.createStorageLocation(S->getType());
31281ad6265SDimitry Andric       Env.setStorageLocation(*S, Loc);
31381ad6265SDimitry Andric 
31481ad6265SDimitry Andric       auto &NullPointerVal =
31581ad6265SDimitry Andric           Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
31681ad6265SDimitry Andric       Env.setValue(Loc, NullPointerVal);
31781ad6265SDimitry Andric       break;
31881ad6265SDimitry Andric     }
319*06c3fb27SDimitry Andric     case CK_NullToMemberPointer:
320*06c3fb27SDimitry Andric       // FIXME: Implement pointers to members. For now, don't associate a value
321*06c3fb27SDimitry Andric       // with this expression.
322*06c3fb27SDimitry Andric       break;
323*06c3fb27SDimitry Andric     case CK_FunctionToPointerDecay: {
324*06c3fb27SDimitry Andric       StorageLocation *PointeeLoc =
325*06c3fb27SDimitry Andric           Env.getStorageLocation(*SubExpr, SkipPast::Reference);
326*06c3fb27SDimitry Andric       if (PointeeLoc == nullptr)
327*06c3fb27SDimitry Andric         break;
328*06c3fb27SDimitry Andric 
329*06c3fb27SDimitry Andric       auto &PointerLoc = Env.createStorageLocation(*S);
330*06c3fb27SDimitry Andric       auto &PointerVal = Env.create<PointerValue>(*PointeeLoc);
331*06c3fb27SDimitry Andric       Env.setStorageLocation(*S, PointerLoc);
332*06c3fb27SDimitry Andric       Env.setValue(PointerLoc, PointerVal);
333*06c3fb27SDimitry Andric       break;
334*06c3fb27SDimitry Andric     }
335*06c3fb27SDimitry Andric     case CK_BuiltinFnToFnPtr:
336*06c3fb27SDimitry Andric       // Despite its name, the result type of `BuiltinFnToFnPtr` is a function,
337*06c3fb27SDimitry Andric       // not a function pointer. In addition, builtin functions can only be
338*06c3fb27SDimitry Andric       // called directly; it is not legal to take their address. We therefore
339*06c3fb27SDimitry Andric       // don't need to create a value or storage location for them.
340*06c3fb27SDimitry Andric       break;
34104eeddc0SDimitry Andric     default:
34204eeddc0SDimitry Andric       break;
34304eeddc0SDimitry Andric     }
34404eeddc0SDimitry Andric   }
34504eeddc0SDimitry Andric 
34604eeddc0SDimitry Andric   void VisitUnaryOperator(const UnaryOperator *S) {
34781ad6265SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
34804eeddc0SDimitry Andric     assert(SubExpr != nullptr);
34904eeddc0SDimitry Andric 
35004eeddc0SDimitry Andric     switch (S->getOpcode()) {
35104eeddc0SDimitry Andric     case UO_Deref: {
352*06c3fb27SDimitry Andric       const auto *SubExprVal =
353*06c3fb27SDimitry Andric           cast_or_null<PointerValue>(Env.getValueStrict(*SubExpr));
35404eeddc0SDimitry Andric       if (SubExprVal == nullptr)
35504eeddc0SDimitry Andric         break;
35604eeddc0SDimitry Andric 
357*06c3fb27SDimitry Andric       Env.setStorageLocationStrict(*S, SubExprVal->getPointeeLoc());
35804eeddc0SDimitry Andric       break;
35904eeddc0SDimitry Andric     }
36004eeddc0SDimitry Andric     case UO_AddrOf: {
361*06c3fb27SDimitry Andric       // FIXME: Model pointers to members.
362*06c3fb27SDimitry Andric       if (S->getType()->isMemberPointerType())
36304eeddc0SDimitry Andric         break;
36404eeddc0SDimitry Andric 
365*06c3fb27SDimitry Andric       if (StorageLocation *PointeeLoc = Env.getStorageLocationStrict(*SubExpr))
366*06c3fb27SDimitry Andric         Env.setValueStrict(*S, Env.create<PointerValue>(*PointeeLoc));
36704eeddc0SDimitry Andric       break;
36804eeddc0SDimitry Andric     }
36981ad6265SDimitry Andric     case UO_LNot: {
37081ad6265SDimitry Andric       auto *SubExprVal =
371*06c3fb27SDimitry Andric           dyn_cast_or_null<BoolValue>(Env.getValueStrict(*SubExpr));
37281ad6265SDimitry Andric       if (SubExprVal == nullptr)
37381ad6265SDimitry Andric         break;
37481ad6265SDimitry Andric 
37581ad6265SDimitry Andric       auto &ExprLoc = Env.createStorageLocation(*S);
37681ad6265SDimitry Andric       Env.setStorageLocation(*S, ExprLoc);
37781ad6265SDimitry Andric       Env.setValue(ExprLoc, Env.makeNot(*SubExprVal));
37881ad6265SDimitry Andric       break;
37981ad6265SDimitry Andric     }
38004eeddc0SDimitry Andric     default:
38104eeddc0SDimitry Andric       break;
38204eeddc0SDimitry Andric     }
38304eeddc0SDimitry Andric   }
38404eeddc0SDimitry Andric 
38504eeddc0SDimitry Andric   void VisitCXXThisExpr(const CXXThisExpr *S) {
38604eeddc0SDimitry Andric     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
38781ad6265SDimitry Andric     if (ThisPointeeLoc == nullptr)
38881ad6265SDimitry Andric       // Unions are not supported yet, and will not have a location for the
38981ad6265SDimitry Andric       // `this` expression's pointee.
39081ad6265SDimitry Andric       return;
39104eeddc0SDimitry Andric 
39204eeddc0SDimitry Andric     auto &Loc = Env.createStorageLocation(*S);
39304eeddc0SDimitry Andric     Env.setStorageLocation(*S, Loc);
394*06c3fb27SDimitry Andric     Env.setValue(Loc, Env.create<PointerValue>(*ThisPointeeLoc));
395*06c3fb27SDimitry Andric   }
396*06c3fb27SDimitry Andric 
397*06c3fb27SDimitry Andric   void VisitCXXNewExpr(const CXXNewExpr *S) {
398*06c3fb27SDimitry Andric     auto &Loc = Env.createStorageLocation(*S);
399*06c3fb27SDimitry Andric     Env.setStorageLocation(*S, Loc);
400*06c3fb27SDimitry Andric     if (Value *Val = Env.createValue(S->getType()))
401*06c3fb27SDimitry Andric       Env.setValue(Loc, *Val);
402*06c3fb27SDimitry Andric   }
403*06c3fb27SDimitry Andric 
404*06c3fb27SDimitry Andric   void VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
405*06c3fb27SDimitry Andric     // Empty method.
406*06c3fb27SDimitry Andric     // We consciously don't do anything on deletes.  Diagnosing double deletes
407*06c3fb27SDimitry Andric     // (for example) should be done by a specific analysis, not by the
408*06c3fb27SDimitry Andric     // framework.
40904eeddc0SDimitry Andric   }
41004eeddc0SDimitry Andric 
411bdd1243dSDimitry Andric   void VisitReturnStmt(const ReturnStmt *S) {
412*06c3fb27SDimitry Andric     if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts)
413bdd1243dSDimitry Andric       return;
414bdd1243dSDimitry Andric 
415bdd1243dSDimitry Andric     auto *Ret = S->getRetValue();
416bdd1243dSDimitry Andric     if (Ret == nullptr)
417bdd1243dSDimitry Andric       return;
418bdd1243dSDimitry Andric 
419*06c3fb27SDimitry Andric     if (Ret->isPRValue()) {
420*06c3fb27SDimitry Andric       auto *Val = Env.getValueStrict(*Ret);
421bdd1243dSDimitry Andric       if (Val == nullptr)
422bdd1243dSDimitry Andric         return;
423bdd1243dSDimitry Andric 
424*06c3fb27SDimitry Andric       // FIXME: Model NRVO.
425*06c3fb27SDimitry Andric       Env.setReturnValue(Val);
426*06c3fb27SDimitry Andric     } else {
427*06c3fb27SDimitry Andric       auto *Loc = Env.getStorageLocationStrict(*Ret);
428*06c3fb27SDimitry Andric       if (Loc == nullptr)
429bdd1243dSDimitry Andric         return;
430bdd1243dSDimitry Andric 
431bdd1243dSDimitry Andric       // FIXME: Model NRVO.
432*06c3fb27SDimitry Andric       Env.setReturnStorageLocation(Loc);
433*06c3fb27SDimitry Andric     }
434bdd1243dSDimitry Andric   }
435bdd1243dSDimitry Andric 
43604eeddc0SDimitry Andric   void VisitMemberExpr(const MemberExpr *S) {
43704eeddc0SDimitry Andric     ValueDecl *Member = S->getMemberDecl();
43804eeddc0SDimitry Andric     assert(Member != nullptr);
43904eeddc0SDimitry Andric 
44004eeddc0SDimitry Andric     // FIXME: Consider assigning pointer values to function member expressions.
44104eeddc0SDimitry Andric     if (Member->isFunctionOrFunctionTemplate())
44204eeddc0SDimitry Andric       return;
44304eeddc0SDimitry Andric 
444bdd1243dSDimitry Andric     // FIXME: if/when we add support for modeling enums, use that support here.
445bdd1243dSDimitry Andric     if (isa<EnumConstantDecl>(Member))
446bdd1243dSDimitry Andric       return;
447bdd1243dSDimitry Andric 
44881ad6265SDimitry Andric     if (auto *D = dyn_cast<VarDecl>(Member)) {
44981ad6265SDimitry Andric       if (D->hasGlobalStorage()) {
450*06c3fb27SDimitry Andric         auto *VarDeclLoc = Env.getStorageLocation(*D);
45181ad6265SDimitry Andric         if (VarDeclLoc == nullptr)
45281ad6265SDimitry Andric           return;
45381ad6265SDimitry Andric 
45481ad6265SDimitry Andric         Env.setStorageLocation(*S, *VarDeclLoc);
45581ad6265SDimitry Andric         return;
45681ad6265SDimitry Andric       }
45781ad6265SDimitry Andric     }
45881ad6265SDimitry Andric 
459*06c3fb27SDimitry Andric     AggregateStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env);
46004eeddc0SDimitry Andric     if (BaseLoc == nullptr)
46104eeddc0SDimitry Andric       return;
46204eeddc0SDimitry Andric 
463*06c3fb27SDimitry Andric     auto *MemberLoc = BaseLoc->getChild(*Member);
464*06c3fb27SDimitry Andric     if (MemberLoc == nullptr)
465*06c3fb27SDimitry Andric       return;
466*06c3fb27SDimitry Andric     Env.setStorageLocationStrict(*S, *MemberLoc);
46704eeddc0SDimitry Andric   }
46804eeddc0SDimitry Andric 
46904eeddc0SDimitry Andric   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
47004eeddc0SDimitry Andric     const Expr *InitExpr = S->getExpr();
47104eeddc0SDimitry Andric     assert(InitExpr != nullptr);
472*06c3fb27SDimitry Andric     propagateValueOrStorageLocation(*InitExpr, *S, Env);
47304eeddc0SDimitry Andric   }
47404eeddc0SDimitry Andric 
47504eeddc0SDimitry Andric   void VisitCXXConstructExpr(const CXXConstructExpr *S) {
47604eeddc0SDimitry Andric     const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
47704eeddc0SDimitry Andric     assert(ConstructorDecl != nullptr);
47804eeddc0SDimitry Andric 
47904eeddc0SDimitry Andric     if (ConstructorDecl->isCopyOrMoveConstructor()) {
480*06c3fb27SDimitry Andric       // It is permissible for a copy/move constructor to have additional
481*06c3fb27SDimitry Andric       // parameters as long as they have default arguments defined for them.
482*06c3fb27SDimitry Andric       assert(S->getNumArgs() != 0);
48304eeddc0SDimitry Andric 
48404eeddc0SDimitry Andric       const Expr *Arg = S->getArg(0);
48504eeddc0SDimitry Andric       assert(Arg != nullptr);
48604eeddc0SDimitry Andric 
487*06c3fb27SDimitry Andric       auto *ArgLoc = cast_or_null<AggregateStorageLocation>(
488*06c3fb27SDimitry Andric           Env.getStorageLocation(*Arg, SkipPast::Reference));
48904eeddc0SDimitry Andric       if (ArgLoc == nullptr)
49004eeddc0SDimitry Andric         return;
49104eeddc0SDimitry Andric 
492*06c3fb27SDimitry Andric       if (S->isElidable()) {
49304eeddc0SDimitry Andric         Env.setStorageLocation(*S, *ArgLoc);
494*06c3fb27SDimitry Andric       } else if (auto *ArgVal = cast_or_null<StructValue>(
495*06c3fb27SDimitry Andric                      Env.getValue(*Arg, SkipPast::Reference))) {
496*06c3fb27SDimitry Andric         auto &Val = *cast<StructValue>(Env.createValue(S->getType()));
497*06c3fb27SDimitry Andric         Env.setValueStrict(*S, Val);
498*06c3fb27SDimitry Andric         copyRecord(ArgVal->getAggregateLoc(), Val.getAggregateLoc(), Env);
49904eeddc0SDimitry Andric       }
50004eeddc0SDimitry Andric       return;
50104eeddc0SDimitry Andric     }
50204eeddc0SDimitry Andric 
503*06c3fb27SDimitry Andric     auto &InitialVal = *cast<StructValue>(Env.createValue(S->getType()));
504*06c3fb27SDimitry Andric     copyRecord(InitialVal.getAggregateLoc(), Env.getResultObjectLocation(*S),
505*06c3fb27SDimitry Andric                Env);
506bdd1243dSDimitry Andric 
507bdd1243dSDimitry Andric     transferInlineCall(S, ConstructorDecl);
50804eeddc0SDimitry Andric   }
50904eeddc0SDimitry Andric 
51004eeddc0SDimitry Andric   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
51104eeddc0SDimitry Andric     if (S->getOperator() == OO_Equal) {
51204eeddc0SDimitry Andric       assert(S->getNumArgs() == 2);
51304eeddc0SDimitry Andric 
51404eeddc0SDimitry Andric       const Expr *Arg0 = S->getArg(0);
51504eeddc0SDimitry Andric       assert(Arg0 != nullptr);
51604eeddc0SDimitry Andric 
51704eeddc0SDimitry Andric       const Expr *Arg1 = S->getArg(1);
51804eeddc0SDimitry Andric       assert(Arg1 != nullptr);
51904eeddc0SDimitry Andric 
52004eeddc0SDimitry Andric       // Evaluate only copy and move assignment operators.
521*06c3fb27SDimitry Andric       const auto *Method =
522*06c3fb27SDimitry Andric           dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee());
523*06c3fb27SDimitry Andric       if (!Method)
524*06c3fb27SDimitry Andric         return;
525*06c3fb27SDimitry Andric       if (!Method->isCopyAssignmentOperator() &&
526*06c3fb27SDimitry Andric           !Method->isMoveAssignmentOperator())
52704eeddc0SDimitry Andric         return;
52804eeddc0SDimitry Andric 
529*06c3fb27SDimitry Andric       auto *LocSrc = cast_or_null<AggregateStorageLocation>(
530*06c3fb27SDimitry Andric           Env.getStorageLocationStrict(*Arg1));
531*06c3fb27SDimitry Andric       auto *LocDst = cast_or_null<AggregateStorageLocation>(
532*06c3fb27SDimitry Andric           Env.getStorageLocationStrict(*Arg0));
53304eeddc0SDimitry Andric 
534*06c3fb27SDimitry Andric       if (LocSrc != nullptr && LocDst != nullptr) {
535*06c3fb27SDimitry Andric         copyRecord(*LocSrc, *LocDst, Env);
536*06c3fb27SDimitry Andric         Env.setStorageLocationStrict(*S, *LocDst);
537*06c3fb27SDimitry Andric       }
53804eeddc0SDimitry Andric     }
53904eeddc0SDimitry Andric   }
54004eeddc0SDimitry Andric 
54104eeddc0SDimitry Andric   void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
54204eeddc0SDimitry Andric     if (S->getCastKind() == CK_ConstructorConversion) {
54304eeddc0SDimitry Andric       const Expr *SubExpr = S->getSubExpr();
54404eeddc0SDimitry Andric       assert(SubExpr != nullptr);
54504eeddc0SDimitry Andric 
546*06c3fb27SDimitry Andric       propagateValue(*SubExpr, *S, Env);
54704eeddc0SDimitry Andric     }
54804eeddc0SDimitry Andric   }
54904eeddc0SDimitry Andric 
55004eeddc0SDimitry Andric   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
55104eeddc0SDimitry Andric     if (Value *Val = Env.createValue(S->getType()))
552*06c3fb27SDimitry Andric       Env.setValueStrict(*S, *Val);
55304eeddc0SDimitry Andric   }
55404eeddc0SDimitry Andric 
55504eeddc0SDimitry Andric   void VisitCallExpr(const CallExpr *S) {
55681ad6265SDimitry Andric     // Of clang's builtins, only `__builtin_expect` is handled explicitly, since
55781ad6265SDimitry Andric     // others (like trap, debugtrap, and unreachable) are handled by CFG
55881ad6265SDimitry Andric     // construction.
55904eeddc0SDimitry Andric     if (S->isCallToStdMove()) {
56004eeddc0SDimitry Andric       assert(S->getNumArgs() == 1);
56104eeddc0SDimitry Andric 
56204eeddc0SDimitry Andric       const Expr *Arg = S->getArg(0);
56304eeddc0SDimitry Andric       assert(Arg != nullptr);
56404eeddc0SDimitry Andric 
56504eeddc0SDimitry Andric       auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
56604eeddc0SDimitry Andric       if (ArgLoc == nullptr)
56704eeddc0SDimitry Andric         return;
56804eeddc0SDimitry Andric 
56904eeddc0SDimitry Andric       Env.setStorageLocation(*S, *ArgLoc);
57081ad6265SDimitry Andric     } else if (S->getDirectCallee() != nullptr &&
57181ad6265SDimitry Andric                S->getDirectCallee()->getBuiltinID() ==
57281ad6265SDimitry Andric                    Builtin::BI__builtin_expect) {
57381ad6265SDimitry Andric       assert(S->getNumArgs() > 0);
57481ad6265SDimitry Andric       assert(S->getArg(0) != nullptr);
57581ad6265SDimitry Andric       // `__builtin_expect` returns by-value, so strip away any potential
57681ad6265SDimitry Andric       // references in the argument.
57781ad6265SDimitry Andric       auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference);
57881ad6265SDimitry Andric       if (ArgLoc == nullptr)
57981ad6265SDimitry Andric         return;
58081ad6265SDimitry Andric       Env.setStorageLocation(*S, *ArgLoc);
581972a253aSDimitry Andric     } else if (const FunctionDecl *F = S->getDirectCallee()) {
582bdd1243dSDimitry Andric       transferInlineCall(S, F);
58304eeddc0SDimitry Andric     }
58404eeddc0SDimitry Andric   }
58504eeddc0SDimitry Andric 
58604eeddc0SDimitry Andric   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
58704eeddc0SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
58804eeddc0SDimitry Andric     assert(SubExpr != nullptr);
58904eeddc0SDimitry Andric 
590*06c3fb27SDimitry Andric     Value *SubExprVal = Env.getValueStrict(*SubExpr);
591*06c3fb27SDimitry Andric     if (SubExprVal == nullptr)
59204eeddc0SDimitry Andric       return;
59304eeddc0SDimitry Andric 
594*06c3fb27SDimitry Andric     if (StructValue *StructVal = dyn_cast<StructValue>(SubExprVal)) {
595*06c3fb27SDimitry Andric       Env.setStorageLocation(*S, StructVal->getAggregateLoc());
596*06c3fb27SDimitry Andric       return;
597*06c3fb27SDimitry Andric     }
598*06c3fb27SDimitry Andric 
599*06c3fb27SDimitry Andric     StorageLocation &Loc = Env.createStorageLocation(*S);
600*06c3fb27SDimitry Andric     Env.setValue(Loc, *SubExprVal);
601*06c3fb27SDimitry Andric     Env.setStorageLocation(*S, Loc);
60204eeddc0SDimitry Andric   }
60304eeddc0SDimitry Andric 
60404eeddc0SDimitry Andric   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
60504eeddc0SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
60604eeddc0SDimitry Andric     assert(SubExpr != nullptr);
60704eeddc0SDimitry Andric 
608*06c3fb27SDimitry Andric     propagateValue(*SubExpr, *S, Env);
60904eeddc0SDimitry Andric   }
61004eeddc0SDimitry Andric 
61104eeddc0SDimitry Andric   void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
61204eeddc0SDimitry Andric     if (S->getCastKind() == CK_NoOp) {
61304eeddc0SDimitry Andric       const Expr *SubExpr = S->getSubExpr();
61404eeddc0SDimitry Andric       assert(SubExpr != nullptr);
61504eeddc0SDimitry Andric 
616*06c3fb27SDimitry Andric       propagateValueOrStorageLocation(*SubExpr, *S, Env);
61704eeddc0SDimitry Andric     }
61804eeddc0SDimitry Andric   }
61904eeddc0SDimitry Andric 
62004eeddc0SDimitry Andric   void VisitConditionalOperator(const ConditionalOperator *S) {
62104eeddc0SDimitry Andric     // FIXME: Revisit this once flow conditions are added to the framework. For
62204eeddc0SDimitry Andric     // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
62304eeddc0SDimitry Andric     // condition.
624*06c3fb27SDimitry Andric     if (S->isGLValue())
625*06c3fb27SDimitry Andric       Env.setStorageLocationStrict(*S, Env.createObject(S->getType()));
626*06c3fb27SDimitry Andric     else if (Value *Val = Env.createValue(S->getType()))
627*06c3fb27SDimitry Andric       Env.setValueStrict(*S, *Val);
62804eeddc0SDimitry Andric   }
62904eeddc0SDimitry Andric 
63004eeddc0SDimitry Andric   void VisitInitListExpr(const InitListExpr *S) {
63104eeddc0SDimitry Andric     QualType Type = S->getType();
63204eeddc0SDimitry Andric 
633*06c3fb27SDimitry Andric     if (!Type->isStructureOrClassType()) {
634*06c3fb27SDimitry Andric       if (auto *Val = Env.createValue(Type))
635*06c3fb27SDimitry Andric         Env.setValueStrict(*S, *Val);
63604eeddc0SDimitry Andric 
63704eeddc0SDimitry Andric       return;
638*06c3fb27SDimitry Andric     }
63904eeddc0SDimitry Andric 
640*06c3fb27SDimitry Andric     std::vector<FieldDecl *> Fields =
641*06c3fb27SDimitry Andric         getFieldsForInitListExpr(Type->getAsRecordDecl());
642*06c3fb27SDimitry Andric     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
64304eeddc0SDimitry Andric 
644*06c3fb27SDimitry Andric     for (auto [Field, Init] : llvm::zip(Fields, S->inits())) {
64504eeddc0SDimitry Andric       assert(Field != nullptr);
64604eeddc0SDimitry Andric       assert(Init != nullptr);
64704eeddc0SDimitry Andric 
648*06c3fb27SDimitry Andric       FieldLocs.insert({Field, &Env.createObject(Field->getType(), Init)});
64904eeddc0SDimitry Andric     }
650*06c3fb27SDimitry Andric 
651*06c3fb27SDimitry Andric     auto &Loc =
652*06c3fb27SDimitry Andric         Env.getDataflowAnalysisContext()
653*06c3fb27SDimitry Andric             .arena()
654*06c3fb27SDimitry Andric             .create<AggregateStorageLocation>(Type, std::move(FieldLocs));
655*06c3fb27SDimitry Andric     StructValue &StructVal = Env.create<StructValue>(Loc);
656*06c3fb27SDimitry Andric 
657*06c3fb27SDimitry Andric     Env.setValue(Loc, StructVal);
658*06c3fb27SDimitry Andric 
659*06c3fb27SDimitry Andric     Env.setValueStrict(*S, StructVal);
660*06c3fb27SDimitry Andric 
66104eeddc0SDimitry Andric     // FIXME: Implement array initialization.
66204eeddc0SDimitry Andric   }
66304eeddc0SDimitry Andric 
66404eeddc0SDimitry Andric   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
665*06c3fb27SDimitry Andric     Env.setValueStrict(*S, Env.getBoolLiteralValue(S->getValue()));
666*06c3fb27SDimitry Andric   }
667*06c3fb27SDimitry Andric 
668*06c3fb27SDimitry Andric   void VisitIntegerLiteral(const IntegerLiteral *S) {
669*06c3fb27SDimitry Andric     Env.setValueStrict(*S, Env.getIntLiteralValue(S->getValue()));
67004eeddc0SDimitry Andric   }
67104eeddc0SDimitry Andric 
67281ad6265SDimitry Andric   void VisitParenExpr(const ParenExpr *S) {
67381ad6265SDimitry Andric     // The CFG does not contain `ParenExpr` as top-level statements in basic
67481ad6265SDimitry Andric     // blocks, however manual traversal to sub-expressions may encounter them.
67581ad6265SDimitry Andric     // Redirect to the sub-expression.
67681ad6265SDimitry Andric     auto *SubExpr = S->getSubExpr();
67781ad6265SDimitry Andric     assert(SubExpr != nullptr);
67881ad6265SDimitry Andric     Visit(SubExpr);
67981ad6265SDimitry Andric   }
68081ad6265SDimitry Andric 
68181ad6265SDimitry Andric   void VisitExprWithCleanups(const ExprWithCleanups *S) {
68281ad6265SDimitry Andric     // The CFG does not contain `ExprWithCleanups` as top-level statements in
68381ad6265SDimitry Andric     // basic blocks, however manual traversal to sub-expressions may encounter
68481ad6265SDimitry Andric     // them. Redirect to the sub-expression.
68581ad6265SDimitry Andric     auto *SubExpr = S->getSubExpr();
68681ad6265SDimitry Andric     assert(SubExpr != nullptr);
68781ad6265SDimitry Andric     Visit(SubExpr);
68881ad6265SDimitry Andric   }
68981ad6265SDimitry Andric 
69004eeddc0SDimitry Andric private:
691*06c3fb27SDimitry Andric   /// Returns the value for the sub-expression `SubExpr` of a logic operator.
69281ad6265SDimitry Andric   BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
69381ad6265SDimitry Andric     // `SubExpr` and its parent logic operator might be part of different basic
69481ad6265SDimitry Andric     // blocks. We try to access the value that is assigned to `SubExpr` in the
69581ad6265SDimitry Andric     // corresponding environment.
696*06c3fb27SDimitry Andric     if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr))
697*06c3fb27SDimitry Andric       if (auto *Val =
698*06c3fb27SDimitry Andric               dyn_cast_or_null<BoolValue>(SubExprEnv->getValueStrict(SubExpr)))
69981ad6265SDimitry Andric         return *Val;
70081ad6265SDimitry Andric 
701*06c3fb27SDimitry Andric     // The sub-expression may lie within a basic block that isn't reachable,
702*06c3fb27SDimitry Andric     // even if we need it to evaluate the current (reachable) expression
703*06c3fb27SDimitry Andric     // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr`
704*06c3fb27SDimitry Andric     // within the current environment and then try to get the value that gets
705*06c3fb27SDimitry Andric     // assigned to it.
706*06c3fb27SDimitry Andric     if (Env.getValueStrict(SubExpr) == nullptr)
70781ad6265SDimitry Andric       Visit(&SubExpr);
708*06c3fb27SDimitry Andric     if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValueStrict(SubExpr)))
70981ad6265SDimitry Andric       return *Val;
71081ad6265SDimitry Andric 
71181ad6265SDimitry Andric     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
71281ad6265SDimitry Andric     // boolean value for it.
71381ad6265SDimitry Andric     return Env.makeAtomicBoolValue();
71481ad6265SDimitry Andric   }
71581ad6265SDimitry Andric 
716bdd1243dSDimitry Andric   // If context sensitivity is enabled, try to analyze the body of the callee
717bdd1243dSDimitry Andric   // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`.
718bdd1243dSDimitry Andric   template <typename E>
719bdd1243dSDimitry Andric   void transferInlineCall(const E *S, const FunctionDecl *F) {
720*06c3fb27SDimitry Andric     const auto &Options = Env.getDataflowAnalysisContext().getOptions();
721bdd1243dSDimitry Andric     if (!(Options.ContextSensitiveOpts &&
722bdd1243dSDimitry Andric           Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))
723bdd1243dSDimitry Andric       return;
724bdd1243dSDimitry Andric 
725*06c3fb27SDimitry Andric     const ControlFlowContext *CFCtx =
726*06c3fb27SDimitry Andric         Env.getDataflowAnalysisContext().getControlFlowContext(F);
727bdd1243dSDimitry Andric     if (!CFCtx)
728bdd1243dSDimitry Andric       return;
729bdd1243dSDimitry Andric 
730bdd1243dSDimitry Andric     // FIXME: We don't support context-sensitive analysis of recursion, so
731bdd1243dSDimitry Andric     // we should return early here if `F` is the same as the `FunctionDecl`
732bdd1243dSDimitry Andric     // holding `S` itself.
733bdd1243dSDimitry Andric 
734bdd1243dSDimitry Andric     auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
735bdd1243dSDimitry Andric 
736bdd1243dSDimitry Andric     auto CalleeEnv = Env.pushCall(S);
737bdd1243dSDimitry Andric 
738bdd1243dSDimitry Andric     // FIXME: Use the same analysis as the caller for the callee. Note,
739bdd1243dSDimitry Andric     // though, that doing so would require support for changing the analysis's
740bdd1243dSDimitry Andric     // ASTContext.
741bdd1243dSDimitry Andric     assert(CFCtx->getDecl() != nullptr &&
742bdd1243dSDimitry Andric            "ControlFlowContexts in the environment should always carry a decl");
743bdd1243dSDimitry Andric     auto Analysis = NoopAnalysis(CFCtx->getDecl()->getASTContext(),
744bdd1243dSDimitry Andric                                  DataflowAnalysisOptions{Options});
745bdd1243dSDimitry Andric 
746bdd1243dSDimitry Andric     auto BlockToOutputState =
747bdd1243dSDimitry Andric         dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
748bdd1243dSDimitry Andric     assert(BlockToOutputState);
749bdd1243dSDimitry Andric     assert(ExitBlock < BlockToOutputState->size());
750bdd1243dSDimitry Andric 
751*06c3fb27SDimitry Andric     auto &ExitState = (*BlockToOutputState)[ExitBlock];
752bdd1243dSDimitry Andric     assert(ExitState);
753bdd1243dSDimitry Andric 
754*06c3fb27SDimitry Andric     Env.popCall(S, ExitState->Env);
755bdd1243dSDimitry Andric   }
756bdd1243dSDimitry Andric 
75781ad6265SDimitry Andric   const StmtToEnvMap &StmtToEnv;
75804eeddc0SDimitry Andric   Environment &Env;
75904eeddc0SDimitry Andric };
76004eeddc0SDimitry Andric 
761*06c3fb27SDimitry Andric } // namespace
762*06c3fb27SDimitry Andric 
763bdd1243dSDimitry Andric void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
764bdd1243dSDimitry Andric   TransferVisitor(StmtToEnv, Env).Visit(&S);
76504eeddc0SDimitry Andric }
76604eeddc0SDimitry Andric 
76704eeddc0SDimitry Andric } // namespace dataflow
76804eeddc0SDimitry Andric } // namespace clang
769