xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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"
2606c3fb27SDimitry 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/Support/Casting.h"
31*5f757f3fSDimitry Andric #include "llvm/Support/Debug.h"
32*5f757f3fSDimitry Andric #include <assert.h>
3304eeddc0SDimitry Andric #include <cassert>
34*5f757f3fSDimitry Andric 
35*5f757f3fSDimitry Andric #define DEBUG_TYPE "dataflow"
3604eeddc0SDimitry Andric 
3704eeddc0SDimitry Andric namespace clang {
3804eeddc0SDimitry Andric namespace dataflow {
3904eeddc0SDimitry Andric 
4006c3fb27SDimitry Andric const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const {
4106c3fb27SDimitry Andric   auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
4206c3fb27SDimitry Andric   assert(BlockIt != CFCtx.getStmtToBlock().end());
4306c3fb27SDimitry Andric   if (!CFCtx.isBlockReachable(*BlockIt->getSecond()))
4406c3fb27SDimitry Andric     return nullptr;
4506c3fb27SDimitry Andric   const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
46*5f757f3fSDimitry Andric   if (!(State))
47*5f757f3fSDimitry Andric     return nullptr;
4806c3fb27SDimitry Andric   return &State->Env;
4904eeddc0SDimitry Andric }
5004eeddc0SDimitry Andric 
5106c3fb27SDimitry Andric static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
5206c3fb27SDimitry Andric                                           Environment &Env) {
53*5f757f3fSDimitry Andric   Value *LHSValue = Env.getValue(LHS);
54*5f757f3fSDimitry Andric   Value *RHSValue = Env.getValue(RHS);
55bdd1243dSDimitry Andric 
5606c3fb27SDimitry Andric   if (LHSValue == RHSValue)
5706c3fb27SDimitry Andric     return Env.getBoolLiteralValue(true);
58bdd1243dSDimitry Andric 
5906c3fb27SDimitry Andric   if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue))
6006c3fb27SDimitry Andric     if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue))
6106c3fb27SDimitry Andric       return Env.makeIff(*LHSBool, *RHSBool);
62bdd1243dSDimitry Andric 
6306c3fb27SDimitry Andric   return Env.makeAtomicBoolValue();
64bdd1243dSDimitry Andric }
65bdd1243dSDimitry Andric 
66bdd1243dSDimitry Andric static BoolValue &unpackValue(BoolValue &V, Environment &Env) {
6706c3fb27SDimitry Andric   if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) {
6806c3fb27SDimitry Andric     auto &A = Env.getDataflowAnalysisContext().arena();
6906c3fb27SDimitry Andric     return A.makeBoolValue(A.makeAtomRef(Top->getAtom()));
70bdd1243dSDimitry Andric   }
7106c3fb27SDimitry Andric   return V;
72bdd1243dSDimitry Andric }
73bdd1243dSDimitry Andric 
74bdd1243dSDimitry Andric // Unpacks the value (if any) associated with `E` and updates `E` to the new
7506c3fb27SDimitry Andric // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion,
7606c3fb27SDimitry Andric // by skipping past the reference.
77bdd1243dSDimitry Andric static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) {
78*5f757f3fSDimitry Andric   auto *Loc = Env.getStorageLocation(E);
79bdd1243dSDimitry Andric   if (Loc == nullptr)
80bdd1243dSDimitry Andric     return nullptr;
81bdd1243dSDimitry Andric   auto *Val = Env.getValue(*Loc);
82bdd1243dSDimitry Andric 
83bdd1243dSDimitry Andric   auto *B = dyn_cast_or_null<BoolValue>(Val);
84bdd1243dSDimitry Andric   if (B == nullptr)
85bdd1243dSDimitry Andric     return Val;
86bdd1243dSDimitry Andric 
87bdd1243dSDimitry Andric   auto &UnpackedVal = unpackValue(*B, Env);
88bdd1243dSDimitry Andric   if (&UnpackedVal == Val)
89bdd1243dSDimitry Andric     return Val;
90bdd1243dSDimitry Andric   Env.setValue(*Loc, UnpackedVal);
91bdd1243dSDimitry Andric   return &UnpackedVal;
92bdd1243dSDimitry Andric }
93bdd1243dSDimitry Andric 
9406c3fb27SDimitry Andric static void propagateValue(const Expr &From, const Expr &To, Environment &Env) {
95*5f757f3fSDimitry Andric   if (auto *Val = Env.getValue(From))
96*5f757f3fSDimitry Andric     Env.setValue(To, *Val);
9706c3fb27SDimitry Andric }
9806c3fb27SDimitry Andric 
9906c3fb27SDimitry Andric static void propagateStorageLocation(const Expr &From, const Expr &To,
10006c3fb27SDimitry Andric                                      Environment &Env) {
101*5f757f3fSDimitry Andric   if (auto *Loc = Env.getStorageLocation(From))
102*5f757f3fSDimitry Andric     Env.setStorageLocation(To, *Loc);
10306c3fb27SDimitry Andric }
10406c3fb27SDimitry Andric 
10506c3fb27SDimitry Andric // Propagates the value or storage location of `From` to `To` in cases where
10606c3fb27SDimitry Andric // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff
10706c3fb27SDimitry Andric // `From` is a glvalue.
10806c3fb27SDimitry Andric static void propagateValueOrStorageLocation(const Expr &From, const Expr &To,
10906c3fb27SDimitry Andric                                             Environment &Env) {
11006c3fb27SDimitry Andric   assert(From.isGLValue() == To.isGLValue());
11106c3fb27SDimitry Andric   if (From.isGLValue())
11206c3fb27SDimitry Andric     propagateStorageLocation(From, To, Env);
11306c3fb27SDimitry Andric   else
11406c3fb27SDimitry Andric     propagateValue(From, To, Env);
11506c3fb27SDimitry Andric }
11606c3fb27SDimitry Andric 
11706c3fb27SDimitry Andric namespace {
11806c3fb27SDimitry Andric 
11904eeddc0SDimitry Andric class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
12004eeddc0SDimitry Andric public:
121bdd1243dSDimitry Andric   TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
122bdd1243dSDimitry Andric       : StmtToEnv(StmtToEnv), Env(Env) {}
12304eeddc0SDimitry Andric 
12404eeddc0SDimitry Andric   void VisitBinaryOperator(const BinaryOperator *S) {
12581ad6265SDimitry Andric     const Expr *LHS = S->getLHS();
12604eeddc0SDimitry Andric     assert(LHS != nullptr);
12781ad6265SDimitry Andric 
12881ad6265SDimitry Andric     const Expr *RHS = S->getRHS();
12981ad6265SDimitry Andric     assert(RHS != nullptr);
13081ad6265SDimitry Andric 
13181ad6265SDimitry Andric     switch (S->getOpcode()) {
13281ad6265SDimitry Andric     case BO_Assign: {
133*5f757f3fSDimitry Andric       auto *LHSLoc = Env.getStorageLocation(*LHS);
13404eeddc0SDimitry Andric       if (LHSLoc == nullptr)
13581ad6265SDimitry Andric         break;
13604eeddc0SDimitry Andric 
137*5f757f3fSDimitry Andric       auto *RHSVal = Env.getValue(*RHS);
13804eeddc0SDimitry Andric       if (RHSVal == nullptr)
13981ad6265SDimitry Andric         break;
14004eeddc0SDimitry Andric 
14104eeddc0SDimitry Andric       // Assign a value to the storage location of the left-hand side.
14204eeddc0SDimitry Andric       Env.setValue(*LHSLoc, *RHSVal);
14304eeddc0SDimitry Andric 
14404eeddc0SDimitry Andric       // Assign a storage location for the whole expression.
14504eeddc0SDimitry Andric       Env.setStorageLocation(*S, *LHSLoc);
14681ad6265SDimitry Andric       break;
14704eeddc0SDimitry Andric     }
14881ad6265SDimitry Andric     case BO_LAnd:
14981ad6265SDimitry Andric     case BO_LOr: {
15081ad6265SDimitry Andric       BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
15181ad6265SDimitry Andric       BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
15281ad6265SDimitry Andric 
15381ad6265SDimitry Andric       if (S->getOpcode() == BO_LAnd)
154*5f757f3fSDimitry Andric         Env.setValue(*S, Env.makeAnd(LHSVal, RHSVal));
15581ad6265SDimitry Andric       else
156*5f757f3fSDimitry Andric         Env.setValue(*S, Env.makeOr(LHSVal, RHSVal));
15781ad6265SDimitry Andric       break;
15881ad6265SDimitry Andric     }
15981ad6265SDimitry Andric     case BO_NE:
16081ad6265SDimitry Andric     case BO_EQ: {
16181ad6265SDimitry Andric       auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
162*5f757f3fSDimitry Andric       Env.setValue(*S, S->getOpcode() == BO_EQ ? LHSEqRHSValue
16381ad6265SDimitry Andric                                                : Env.makeNot(LHSEqRHSValue));
16481ad6265SDimitry Andric       break;
16581ad6265SDimitry Andric     }
16681ad6265SDimitry Andric     case BO_Comma: {
16706c3fb27SDimitry Andric       propagateValueOrStorageLocation(*RHS, *S, Env);
16881ad6265SDimitry Andric       break;
16981ad6265SDimitry Andric     }
17081ad6265SDimitry Andric     default:
17181ad6265SDimitry Andric       break;
17281ad6265SDimitry Andric     }
17304eeddc0SDimitry Andric   }
17404eeddc0SDimitry Andric 
17504eeddc0SDimitry Andric   void VisitDeclRefExpr(const DeclRefExpr *S) {
176bdd1243dSDimitry Andric     const ValueDecl *VD = S->getDecl();
177bdd1243dSDimitry Andric     assert(VD != nullptr);
17806c3fb27SDimitry Andric 
179*5f757f3fSDimitry Andric     // Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a
180*5f757f3fSDimitry Andric     // `StorageLocation`, and there's also no sensible `Value` that we can
181*5f757f3fSDimitry Andric     // assign to them. Examples:
182*5f757f3fSDimitry Andric     // - Non-static member variables
183*5f757f3fSDimitry Andric     // - Non static member functions
184*5f757f3fSDimitry Andric     //   Note: Member operators are an exception to this, but apparently only
185*5f757f3fSDimitry Andric     //   if the `DeclRefExpr` is used within the callee of a
186*5f757f3fSDimitry Andric     //   `CXXOperatorCallExpr`. In other cases, for example when applying the
187*5f757f3fSDimitry Andric     //   address-of operator, the `DeclRefExpr` is a prvalue.
188*5f757f3fSDimitry Andric     if (!S->isGLValue())
18906c3fb27SDimitry Andric       return;
19006c3fb27SDimitry Andric 
19106c3fb27SDimitry Andric     auto *DeclLoc = Env.getStorageLocation(*VD);
19204eeddc0SDimitry Andric     if (DeclLoc == nullptr)
19304eeddc0SDimitry Andric       return;
19404eeddc0SDimitry Andric 
195*5f757f3fSDimitry Andric     Env.setStorageLocation(*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 
20306c3fb27SDimitry Andric     ProcessVarDecl(D);
20406c3fb27SDimitry Andric   }
20506c3fb27SDimitry Andric 
20606c3fb27SDimitry 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 
21106c3fb27SDimitry Andric     // If this is the holding variable for a `BindingDecl`, we may already
21206c3fb27SDimitry Andric     // have a storage location set up -- so check. (See also explanation below
21306c3fb27SDimitry Andric     // where we process the `BindingDecl`.)
21406c3fb27SDimitry Andric     if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr)
21504eeddc0SDimitry Andric       return;
21604eeddc0SDimitry Andric 
21706c3fb27SDimitry Andric     assert(Env.getStorageLocation(D) == nullptr);
21804eeddc0SDimitry Andric 
21906c3fb27SDimitry Andric     Env.setStorageLocation(D, Env.createObject(D));
22081ad6265SDimitry Andric 
22106c3fb27SDimitry Andric     // `DecompositionDecl` must be handled after we've interpreted the loc
22206c3fb27SDimitry Andric     // itself, because the binding expression refers back to the
22306c3fb27SDimitry 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 
241*5f757f3fSDimitry Andric           if (auto *Loc = Env.getStorageLocation(*ME))
24281ad6265SDimitry Andric             Env.setStorageLocation(*B, *Loc);
243bdd1243dSDimitry Andric         } else if (auto *VD = B->getHoldingVar()) {
24406c3fb27SDimitry Andric           // Holding vars are used to back the `BindingDecl`s of tuple-like
24506c3fb27SDimitry Andric           // types. The holding var declarations appear after the
24606c3fb27SDimitry Andric           // `DecompositionDecl`, so we have to explicitly process them here
24706c3fb27SDimitry Andric           // to know their storage location. They will be processed a second
24806c3fb27SDimitry Andric           // time when we visit their `VarDecl`s, so we have code that protects
24906c3fb27SDimitry Andric           // against this above.
25006c3fb27SDimitry Andric           ProcessVarDecl(*VD);
25106c3fb27SDimitry Andric           auto *VDLoc = Env.getStorageLocation(*VD);
25206c3fb27SDimitry Andric           assert(VDLoc != nullptr);
25306c3fb27SDimitry 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.
26806c3fb27SDimitry Andric       if (auto *SubExprVal =
269*5f757f3fSDimitry Andric               dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr)))
270*5f757f3fSDimitry Andric         Env.setValue(*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*5f757f3fSDimitry Andric         Env.setValue(*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*5f757f3fSDimitry Andric       // need to unpack any nested `Top`s.
281bdd1243dSDimitry Andric       auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env);
28204eeddc0SDimitry Andric       if (SubExprVal == nullptr)
28304eeddc0SDimitry Andric         break;
28404eeddc0SDimitry Andric 
285*5f757f3fSDimitry Andric       Env.setValue(*S, *SubExprVal);
28604eeddc0SDimitry Andric       break;
28704eeddc0SDimitry Andric     }
28881ad6265SDimitry Andric 
28981ad6265SDimitry Andric     case CK_IntegralCast:
29081ad6265SDimitry Andric       // FIXME: This cast creates a new integral value from the
29181ad6265SDimitry Andric       // subexpression. But, because we don't model integers, we don't
29281ad6265SDimitry Andric       // distinguish between this new value and the underlying one. If integer
29381ad6265SDimitry Andric       // modeling is added, then update this code to create a fresh location and
29481ad6265SDimitry Andric       // value.
29581ad6265SDimitry Andric     case CK_UncheckedDerivedToBase:
29681ad6265SDimitry Andric     case CK_ConstructorConversion:
29781ad6265SDimitry Andric     case CK_UserDefinedConversion:
29881ad6265SDimitry Andric       // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
29981ad6265SDimitry Andric       // CK_ConstructorConversion, and CK_UserDefinedConversion.
30004eeddc0SDimitry Andric     case CK_NoOp: {
30104eeddc0SDimitry Andric       // FIXME: Consider making `Environment::getStorageLocation` skip noop
30206c3fb27SDimitry Andric       // expressions (this and other similar expressions in the file) instead
30306c3fb27SDimitry Andric       // of assigning them storage locations.
30406c3fb27SDimitry Andric       propagateValueOrStorageLocation(*SubExpr, *S, Env);
30504eeddc0SDimitry Andric       break;
30604eeddc0SDimitry Andric     }
30706c3fb27SDimitry Andric     case CK_NullToPointer: {
30881ad6265SDimitry Andric       auto &NullPointerVal =
30981ad6265SDimitry Andric           Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
310*5f757f3fSDimitry Andric       Env.setValue(*S, NullPointerVal);
31181ad6265SDimitry Andric       break;
31281ad6265SDimitry Andric     }
31306c3fb27SDimitry Andric     case CK_NullToMemberPointer:
31406c3fb27SDimitry Andric       // FIXME: Implement pointers to members. For now, don't associate a value
31506c3fb27SDimitry Andric       // with this expression.
31606c3fb27SDimitry Andric       break;
31706c3fb27SDimitry Andric     case CK_FunctionToPointerDecay: {
318*5f757f3fSDimitry Andric       StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr);
31906c3fb27SDimitry Andric       if (PointeeLoc == nullptr)
32006c3fb27SDimitry Andric         break;
32106c3fb27SDimitry Andric 
322*5f757f3fSDimitry Andric       Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc));
32306c3fb27SDimitry Andric       break;
32406c3fb27SDimitry Andric     }
32506c3fb27SDimitry Andric     case CK_BuiltinFnToFnPtr:
32606c3fb27SDimitry Andric       // Despite its name, the result type of `BuiltinFnToFnPtr` is a function,
32706c3fb27SDimitry Andric       // not a function pointer. In addition, builtin functions can only be
32806c3fb27SDimitry Andric       // called directly; it is not legal to take their address. We therefore
32906c3fb27SDimitry Andric       // don't need to create a value or storage location for them.
33006c3fb27SDimitry Andric       break;
33104eeddc0SDimitry Andric     default:
33204eeddc0SDimitry Andric       break;
33304eeddc0SDimitry Andric     }
33404eeddc0SDimitry Andric   }
33504eeddc0SDimitry Andric 
33604eeddc0SDimitry Andric   void VisitUnaryOperator(const UnaryOperator *S) {
33781ad6265SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
33804eeddc0SDimitry Andric     assert(SubExpr != nullptr);
33904eeddc0SDimitry Andric 
34004eeddc0SDimitry Andric     switch (S->getOpcode()) {
34104eeddc0SDimitry Andric     case UO_Deref: {
34206c3fb27SDimitry Andric       const auto *SubExprVal =
343*5f757f3fSDimitry Andric           cast_or_null<PointerValue>(Env.getValue(*SubExpr));
34404eeddc0SDimitry Andric       if (SubExprVal == nullptr)
34504eeddc0SDimitry Andric         break;
34604eeddc0SDimitry Andric 
347*5f757f3fSDimitry Andric       Env.setStorageLocation(*S, SubExprVal->getPointeeLoc());
34804eeddc0SDimitry Andric       break;
34904eeddc0SDimitry Andric     }
35004eeddc0SDimitry Andric     case UO_AddrOf: {
35106c3fb27SDimitry Andric       // FIXME: Model pointers to members.
35206c3fb27SDimitry Andric       if (S->getType()->isMemberPointerType())
35304eeddc0SDimitry Andric         break;
35404eeddc0SDimitry Andric 
355*5f757f3fSDimitry Andric       if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr))
356*5f757f3fSDimitry Andric         Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc));
35704eeddc0SDimitry Andric       break;
35804eeddc0SDimitry Andric     }
35981ad6265SDimitry Andric     case UO_LNot: {
360*5f757f3fSDimitry Andric       auto *SubExprVal = dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr));
36181ad6265SDimitry Andric       if (SubExprVal == nullptr)
36281ad6265SDimitry Andric         break;
36381ad6265SDimitry Andric 
364*5f757f3fSDimitry Andric       Env.setValue(*S, Env.makeNot(*SubExprVal));
36581ad6265SDimitry Andric       break;
36681ad6265SDimitry Andric     }
36704eeddc0SDimitry Andric     default:
36804eeddc0SDimitry Andric       break;
36904eeddc0SDimitry Andric     }
37004eeddc0SDimitry Andric   }
37104eeddc0SDimitry Andric 
37204eeddc0SDimitry Andric   void VisitCXXThisExpr(const CXXThisExpr *S) {
37304eeddc0SDimitry Andric     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
37481ad6265SDimitry Andric     if (ThisPointeeLoc == nullptr)
37581ad6265SDimitry Andric       // Unions are not supported yet, and will not have a location for the
37681ad6265SDimitry Andric       // `this` expression's pointee.
37781ad6265SDimitry Andric       return;
37804eeddc0SDimitry Andric 
379*5f757f3fSDimitry Andric     Env.setValue(*S, Env.create<PointerValue>(*ThisPointeeLoc));
38006c3fb27SDimitry Andric   }
38106c3fb27SDimitry Andric 
38206c3fb27SDimitry Andric   void VisitCXXNewExpr(const CXXNewExpr *S) {
38306c3fb27SDimitry Andric     if (Value *Val = Env.createValue(S->getType()))
384*5f757f3fSDimitry Andric       Env.setValue(*S, *Val);
38506c3fb27SDimitry Andric   }
38606c3fb27SDimitry Andric 
38706c3fb27SDimitry Andric   void VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
38806c3fb27SDimitry Andric     // Empty method.
38906c3fb27SDimitry Andric     // We consciously don't do anything on deletes.  Diagnosing double deletes
39006c3fb27SDimitry Andric     // (for example) should be done by a specific analysis, not by the
39106c3fb27SDimitry Andric     // framework.
39204eeddc0SDimitry Andric   }
39304eeddc0SDimitry Andric 
394bdd1243dSDimitry Andric   void VisitReturnStmt(const ReturnStmt *S) {
39506c3fb27SDimitry Andric     if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts)
396bdd1243dSDimitry Andric       return;
397bdd1243dSDimitry Andric 
398bdd1243dSDimitry Andric     auto *Ret = S->getRetValue();
399bdd1243dSDimitry Andric     if (Ret == nullptr)
400bdd1243dSDimitry Andric       return;
401bdd1243dSDimitry Andric 
40206c3fb27SDimitry Andric     if (Ret->isPRValue()) {
403*5f757f3fSDimitry Andric       auto *Val = Env.getValue(*Ret);
404bdd1243dSDimitry Andric       if (Val == nullptr)
405bdd1243dSDimitry Andric         return;
406bdd1243dSDimitry Andric 
40706c3fb27SDimitry Andric       // FIXME: Model NRVO.
40806c3fb27SDimitry Andric       Env.setReturnValue(Val);
40906c3fb27SDimitry Andric     } else {
410*5f757f3fSDimitry Andric       auto *Loc = Env.getStorageLocation(*Ret);
41106c3fb27SDimitry Andric       if (Loc == nullptr)
412bdd1243dSDimitry Andric         return;
413bdd1243dSDimitry Andric 
414bdd1243dSDimitry Andric       // FIXME: Model NRVO.
41506c3fb27SDimitry Andric       Env.setReturnStorageLocation(Loc);
41606c3fb27SDimitry Andric     }
417bdd1243dSDimitry Andric   }
418bdd1243dSDimitry Andric 
41904eeddc0SDimitry Andric   void VisitMemberExpr(const MemberExpr *S) {
42004eeddc0SDimitry Andric     ValueDecl *Member = S->getMemberDecl();
42104eeddc0SDimitry Andric     assert(Member != nullptr);
42204eeddc0SDimitry Andric 
42304eeddc0SDimitry Andric     // FIXME: Consider assigning pointer values to function member expressions.
42404eeddc0SDimitry Andric     if (Member->isFunctionOrFunctionTemplate())
42504eeddc0SDimitry Andric       return;
42604eeddc0SDimitry Andric 
427bdd1243dSDimitry Andric     // FIXME: if/when we add support for modeling enums, use that support here.
428bdd1243dSDimitry Andric     if (isa<EnumConstantDecl>(Member))
429bdd1243dSDimitry Andric       return;
430bdd1243dSDimitry Andric 
43181ad6265SDimitry Andric     if (auto *D = dyn_cast<VarDecl>(Member)) {
43281ad6265SDimitry Andric       if (D->hasGlobalStorage()) {
43306c3fb27SDimitry Andric         auto *VarDeclLoc = Env.getStorageLocation(*D);
43481ad6265SDimitry Andric         if (VarDeclLoc == nullptr)
43581ad6265SDimitry Andric           return;
43681ad6265SDimitry Andric 
43781ad6265SDimitry Andric         Env.setStorageLocation(*S, *VarDeclLoc);
43881ad6265SDimitry Andric         return;
43981ad6265SDimitry Andric       }
44081ad6265SDimitry Andric     }
44181ad6265SDimitry Andric 
442*5f757f3fSDimitry Andric     RecordStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env);
44304eeddc0SDimitry Andric     if (BaseLoc == nullptr)
44404eeddc0SDimitry Andric       return;
44504eeddc0SDimitry Andric 
44606c3fb27SDimitry Andric     auto *MemberLoc = BaseLoc->getChild(*Member);
44706c3fb27SDimitry Andric     if (MemberLoc == nullptr)
44806c3fb27SDimitry Andric       return;
449*5f757f3fSDimitry Andric     Env.setStorageLocation(*S, *MemberLoc);
45004eeddc0SDimitry Andric   }
45104eeddc0SDimitry Andric 
45204eeddc0SDimitry Andric   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
45304eeddc0SDimitry Andric     const Expr *InitExpr = S->getExpr();
45404eeddc0SDimitry Andric     assert(InitExpr != nullptr);
45506c3fb27SDimitry Andric     propagateValueOrStorageLocation(*InitExpr, *S, Env);
45604eeddc0SDimitry Andric   }
45704eeddc0SDimitry Andric 
45804eeddc0SDimitry Andric   void VisitCXXConstructExpr(const CXXConstructExpr *S) {
45904eeddc0SDimitry Andric     const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
46004eeddc0SDimitry Andric     assert(ConstructorDecl != nullptr);
46104eeddc0SDimitry Andric 
46204eeddc0SDimitry Andric     if (ConstructorDecl->isCopyOrMoveConstructor()) {
46306c3fb27SDimitry Andric       // It is permissible for a copy/move constructor to have additional
46406c3fb27SDimitry Andric       // parameters as long as they have default arguments defined for them.
46506c3fb27SDimitry Andric       assert(S->getNumArgs() != 0);
46604eeddc0SDimitry Andric 
46704eeddc0SDimitry Andric       const Expr *Arg = S->getArg(0);
46804eeddc0SDimitry Andric       assert(Arg != nullptr);
46904eeddc0SDimitry Andric 
470*5f757f3fSDimitry Andric       auto *ArgLoc =
471*5f757f3fSDimitry Andric           cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg));
47204eeddc0SDimitry Andric       if (ArgLoc == nullptr)
47304eeddc0SDimitry Andric         return;
47404eeddc0SDimitry Andric 
47506c3fb27SDimitry Andric       if (S->isElidable()) {
476*5f757f3fSDimitry Andric         if (Value *Val = Env.getValue(*ArgLoc))
477*5f757f3fSDimitry Andric           Env.setValue(*S, *Val);
478*5f757f3fSDimitry Andric       } else {
479*5f757f3fSDimitry Andric         auto &Val = *cast<RecordValue>(Env.createValue(S->getType()));
480*5f757f3fSDimitry Andric         Env.setValue(*S, Val);
481*5f757f3fSDimitry Andric         copyRecord(*ArgLoc, Val.getLoc(), Env);
48204eeddc0SDimitry Andric       }
48304eeddc0SDimitry Andric       return;
48404eeddc0SDimitry Andric     }
48504eeddc0SDimitry Andric 
486*5f757f3fSDimitry Andric     // `CXXConstructExpr` can have array type if default-initializing an array
487*5f757f3fSDimitry Andric     // of records, and we currently can't create values for arrays. So check if
488*5f757f3fSDimitry Andric     // we've got a record type.
489*5f757f3fSDimitry Andric     if (S->getType()->isRecordType()) {
490*5f757f3fSDimitry Andric       auto &InitialVal = *cast<RecordValue>(Env.createValue(S->getType()));
491*5f757f3fSDimitry Andric       Env.setValue(*S, InitialVal);
492*5f757f3fSDimitry Andric       copyRecord(InitialVal.getLoc(), Env.getResultObjectLocation(*S), Env);
493*5f757f3fSDimitry Andric     }
494bdd1243dSDimitry Andric 
495bdd1243dSDimitry Andric     transferInlineCall(S, ConstructorDecl);
49604eeddc0SDimitry Andric   }
49704eeddc0SDimitry Andric 
49804eeddc0SDimitry Andric   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
49904eeddc0SDimitry Andric     if (S->getOperator() == OO_Equal) {
50004eeddc0SDimitry Andric       assert(S->getNumArgs() == 2);
50104eeddc0SDimitry Andric 
50204eeddc0SDimitry Andric       const Expr *Arg0 = S->getArg(0);
50304eeddc0SDimitry Andric       assert(Arg0 != nullptr);
50404eeddc0SDimitry Andric 
50504eeddc0SDimitry Andric       const Expr *Arg1 = S->getArg(1);
50604eeddc0SDimitry Andric       assert(Arg1 != nullptr);
50704eeddc0SDimitry Andric 
50804eeddc0SDimitry Andric       // Evaluate only copy and move assignment operators.
50906c3fb27SDimitry Andric       const auto *Method =
51006c3fb27SDimitry Andric           dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee());
51106c3fb27SDimitry Andric       if (!Method)
51206c3fb27SDimitry Andric         return;
51306c3fb27SDimitry Andric       if (!Method->isCopyAssignmentOperator() &&
51406c3fb27SDimitry Andric           !Method->isMoveAssignmentOperator())
51504eeddc0SDimitry Andric         return;
51604eeddc0SDimitry Andric 
517*5f757f3fSDimitry Andric       RecordStorageLocation *LocSrc = nullptr;
518*5f757f3fSDimitry Andric       if (Arg1->isPRValue()) {
519*5f757f3fSDimitry Andric         if (auto *Val = cast_or_null<RecordValue>(Env.getValue(*Arg1)))
520*5f757f3fSDimitry Andric           LocSrc = &Val->getLoc();
521*5f757f3fSDimitry Andric       } else {
522*5f757f3fSDimitry Andric         LocSrc =
523*5f757f3fSDimitry Andric             cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg1));
52406c3fb27SDimitry Andric       }
525*5f757f3fSDimitry Andric       auto *LocDst =
526*5f757f3fSDimitry Andric           cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg0));
527*5f757f3fSDimitry Andric 
528*5f757f3fSDimitry Andric       if (LocSrc == nullptr || LocDst == nullptr)
529*5f757f3fSDimitry Andric         return;
530*5f757f3fSDimitry Andric 
531*5f757f3fSDimitry Andric       // The assignment operators are different from the type of the destination
532*5f757f3fSDimitry Andric       // in this model (i.e. in one of their base classes). This must be very
533*5f757f3fSDimitry Andric       // rare and we just bail.
534*5f757f3fSDimitry Andric       if (Method->getFunctionObjectParameterType()
535*5f757f3fSDimitry Andric               .getCanonicalType()
536*5f757f3fSDimitry Andric               .getUnqualifiedType() !=
537*5f757f3fSDimitry Andric           LocDst->getType().getCanonicalType().getUnqualifiedType())
538*5f757f3fSDimitry Andric         return;
539*5f757f3fSDimitry Andric 
540*5f757f3fSDimitry Andric       copyRecord(*LocSrc, *LocDst, Env);
541*5f757f3fSDimitry Andric       Env.setStorageLocation(*S, *LocDst);
54204eeddc0SDimitry Andric     }
54304eeddc0SDimitry Andric   }
54404eeddc0SDimitry Andric 
54504eeddc0SDimitry Andric   void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
54604eeddc0SDimitry Andric     if (S->getCastKind() == CK_ConstructorConversion) {
54704eeddc0SDimitry Andric       const Expr *SubExpr = S->getSubExpr();
54804eeddc0SDimitry Andric       assert(SubExpr != nullptr);
54904eeddc0SDimitry Andric 
55006c3fb27SDimitry Andric       propagateValue(*SubExpr, *S, Env);
55104eeddc0SDimitry Andric     }
55204eeddc0SDimitry Andric   }
55304eeddc0SDimitry Andric 
55404eeddc0SDimitry Andric   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
55504eeddc0SDimitry Andric     if (Value *Val = Env.createValue(S->getType()))
556*5f757f3fSDimitry Andric       Env.setValue(*S, *Val);
55704eeddc0SDimitry Andric   }
55804eeddc0SDimitry Andric 
55904eeddc0SDimitry Andric   void VisitCallExpr(const CallExpr *S) {
56081ad6265SDimitry Andric     // Of clang's builtins, only `__builtin_expect` is handled explicitly, since
56181ad6265SDimitry Andric     // others (like trap, debugtrap, and unreachable) are handled by CFG
56281ad6265SDimitry Andric     // construction.
56304eeddc0SDimitry Andric     if (S->isCallToStdMove()) {
56404eeddc0SDimitry Andric       assert(S->getNumArgs() == 1);
56504eeddc0SDimitry Andric 
56604eeddc0SDimitry Andric       const Expr *Arg = S->getArg(0);
56704eeddc0SDimitry Andric       assert(Arg != nullptr);
56804eeddc0SDimitry Andric 
569*5f757f3fSDimitry Andric       auto *ArgLoc = Env.getStorageLocation(*Arg);
57004eeddc0SDimitry Andric       if (ArgLoc == nullptr)
57104eeddc0SDimitry Andric         return;
57204eeddc0SDimitry Andric 
57304eeddc0SDimitry Andric       Env.setStorageLocation(*S, *ArgLoc);
57481ad6265SDimitry Andric     } else if (S->getDirectCallee() != nullptr &&
57581ad6265SDimitry Andric                S->getDirectCallee()->getBuiltinID() ==
57681ad6265SDimitry Andric                    Builtin::BI__builtin_expect) {
57781ad6265SDimitry Andric       assert(S->getNumArgs() > 0);
57881ad6265SDimitry Andric       assert(S->getArg(0) != nullptr);
579*5f757f3fSDimitry Andric       auto *ArgVal = Env.getValue(*S->getArg(0));
580*5f757f3fSDimitry Andric       if (ArgVal == nullptr)
58181ad6265SDimitry Andric         return;
582*5f757f3fSDimitry Andric       Env.setValue(*S, *ArgVal);
583972a253aSDimitry Andric     } else if (const FunctionDecl *F = S->getDirectCallee()) {
584bdd1243dSDimitry Andric       transferInlineCall(S, F);
58504eeddc0SDimitry Andric     }
58604eeddc0SDimitry Andric   }
58704eeddc0SDimitry Andric 
58804eeddc0SDimitry Andric   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
58904eeddc0SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
59004eeddc0SDimitry Andric     assert(SubExpr != nullptr);
59104eeddc0SDimitry Andric 
592*5f757f3fSDimitry Andric     Value *SubExprVal = Env.getValue(*SubExpr);
59306c3fb27SDimitry Andric     if (SubExprVal == nullptr)
59404eeddc0SDimitry Andric       return;
59504eeddc0SDimitry Andric 
596*5f757f3fSDimitry Andric     if (RecordValue *RecordVal = dyn_cast<RecordValue>(SubExprVal)) {
597*5f757f3fSDimitry Andric       Env.setStorageLocation(*S, RecordVal->getLoc());
59806c3fb27SDimitry Andric       return;
59906c3fb27SDimitry Andric     }
60006c3fb27SDimitry Andric 
60106c3fb27SDimitry Andric     StorageLocation &Loc = Env.createStorageLocation(*S);
60206c3fb27SDimitry Andric     Env.setValue(Loc, *SubExprVal);
60306c3fb27SDimitry Andric     Env.setStorageLocation(*S, Loc);
60404eeddc0SDimitry Andric   }
60504eeddc0SDimitry Andric 
60604eeddc0SDimitry Andric   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
60704eeddc0SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
60804eeddc0SDimitry Andric     assert(SubExpr != nullptr);
60904eeddc0SDimitry Andric 
61006c3fb27SDimitry Andric     propagateValue(*SubExpr, *S, Env);
61104eeddc0SDimitry Andric   }
61204eeddc0SDimitry Andric 
61304eeddc0SDimitry Andric   void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
61404eeddc0SDimitry Andric     if (S->getCastKind() == CK_NoOp) {
61504eeddc0SDimitry Andric       const Expr *SubExpr = S->getSubExpr();
61604eeddc0SDimitry Andric       assert(SubExpr != nullptr);
61704eeddc0SDimitry Andric 
61806c3fb27SDimitry Andric       propagateValueOrStorageLocation(*SubExpr, *S, Env);
61904eeddc0SDimitry Andric     }
62004eeddc0SDimitry Andric   }
62104eeddc0SDimitry Andric 
62204eeddc0SDimitry Andric   void VisitConditionalOperator(const ConditionalOperator *S) {
62304eeddc0SDimitry Andric     // FIXME: Revisit this once flow conditions are added to the framework. For
62404eeddc0SDimitry Andric     // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
62504eeddc0SDimitry Andric     // condition.
626*5f757f3fSDimitry Andric     // When we do this, we will need to retrieve the values of the operands from
627*5f757f3fSDimitry Andric     // the environments for the basic blocks they are computed in, in a similar
628*5f757f3fSDimitry Andric     // way to how this is done for short-circuited logical operators in
629*5f757f3fSDimitry Andric     // `getLogicOperatorSubExprValue()`.
63006c3fb27SDimitry Andric     if (S->isGLValue())
631*5f757f3fSDimitry Andric       Env.setStorageLocation(*S, Env.createObject(S->getType()));
63206c3fb27SDimitry Andric     else if (Value *Val = Env.createValue(S->getType()))
633*5f757f3fSDimitry Andric       Env.setValue(*S, *Val);
63404eeddc0SDimitry Andric   }
63504eeddc0SDimitry Andric 
63604eeddc0SDimitry Andric   void VisitInitListExpr(const InitListExpr *S) {
63704eeddc0SDimitry Andric     QualType Type = S->getType();
63804eeddc0SDimitry Andric 
63906c3fb27SDimitry Andric     if (!Type->isStructureOrClassType()) {
64006c3fb27SDimitry Andric       if (auto *Val = Env.createValue(Type))
641*5f757f3fSDimitry Andric         Env.setValue(*S, *Val);
64204eeddc0SDimitry Andric 
64304eeddc0SDimitry Andric       return;
64406c3fb27SDimitry Andric     }
64504eeddc0SDimitry Andric 
646*5f757f3fSDimitry Andric     // In case the initializer list is transparent, we just need to propagate
647*5f757f3fSDimitry Andric     // the value that it contains.
648*5f757f3fSDimitry Andric     if (S->isSemanticForm() && S->isTransparent()) {
649*5f757f3fSDimitry Andric       propagateValue(*S->getInit(0), *S, Env);
650*5f757f3fSDimitry Andric       return;
65104eeddc0SDimitry Andric     }
65206c3fb27SDimitry Andric 
653*5f757f3fSDimitry Andric     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
65406c3fb27SDimitry Andric 
655*5f757f3fSDimitry Andric     // This only contains the direct fields for the given type.
656*5f757f3fSDimitry Andric     std::vector<FieldDecl *> FieldsForInit =
657*5f757f3fSDimitry Andric         getFieldsForInitListExpr(Type->getAsRecordDecl());
65806c3fb27SDimitry Andric 
659*5f757f3fSDimitry Andric     // `S->inits()` contains all the initializer epressions, including the
660*5f757f3fSDimitry Andric     // ones for direct base classes.
661*5f757f3fSDimitry Andric     auto Inits = S->inits();
662*5f757f3fSDimitry Andric     size_t InitIdx = 0;
663*5f757f3fSDimitry Andric 
664*5f757f3fSDimitry Andric     // Initialize base classes.
665*5f757f3fSDimitry Andric     if (auto* R = S->getType()->getAsCXXRecordDecl()) {
666*5f757f3fSDimitry Andric       assert(FieldsForInit.size() + R->getNumBases() == Inits.size());
667*5f757f3fSDimitry Andric       for ([[maybe_unused]] const CXXBaseSpecifier &Base : R->bases()) {
668*5f757f3fSDimitry Andric         assert(InitIdx < Inits.size());
669*5f757f3fSDimitry Andric         auto Init = Inits[InitIdx++];
670*5f757f3fSDimitry Andric         assert(Base.getType().getCanonicalType() ==
671*5f757f3fSDimitry Andric                Init->getType().getCanonicalType());
672*5f757f3fSDimitry Andric         auto* BaseVal = cast_or_null<RecordValue>(Env.getValue(*Init));
673*5f757f3fSDimitry Andric         if (!BaseVal)
674*5f757f3fSDimitry Andric           BaseVal = cast<RecordValue>(Env.createValue(Init->getType()));
675*5f757f3fSDimitry Andric         // Take ownership of the fields of the `RecordValue` for the base class
676*5f757f3fSDimitry Andric         // and incorporate them into the "flattened" set of fields for the
677*5f757f3fSDimitry Andric         // derived class.
678*5f757f3fSDimitry Andric         auto Children = BaseVal->getLoc().children();
679*5f757f3fSDimitry Andric         FieldLocs.insert(Children.begin(), Children.end());
680*5f757f3fSDimitry Andric       }
681*5f757f3fSDimitry Andric     }
682*5f757f3fSDimitry Andric 
683*5f757f3fSDimitry Andric     assert(FieldsForInit.size() == Inits.size() - InitIdx);
684*5f757f3fSDimitry Andric     for (auto Field : FieldsForInit) {
685*5f757f3fSDimitry Andric       assert(InitIdx < Inits.size());
686*5f757f3fSDimitry Andric       auto Init = Inits[InitIdx++];
687*5f757f3fSDimitry Andric       assert(
688*5f757f3fSDimitry Andric           // The types are same, or
689*5f757f3fSDimitry Andric           Field->getType().getCanonicalType().getUnqualifiedType() ==
690*5f757f3fSDimitry Andric               Init->getType().getCanonicalType().getUnqualifiedType() ||
691*5f757f3fSDimitry Andric           // The field's type is T&, and initializer is T
692*5f757f3fSDimitry Andric           (Field->getType()->isReferenceType() &&
693*5f757f3fSDimitry Andric            Field->getType().getCanonicalType()->getPointeeType() ==
694*5f757f3fSDimitry Andric                Init->getType().getCanonicalType()));
695*5f757f3fSDimitry Andric       auto& Loc = Env.createObject(Field->getType(), Init);
696*5f757f3fSDimitry Andric       FieldLocs.insert({Field, &Loc});
697*5f757f3fSDimitry Andric     }
698*5f757f3fSDimitry Andric 
699*5f757f3fSDimitry Andric     // Check that we satisfy the invariant that a `RecordStorageLoation`
700*5f757f3fSDimitry Andric     // contains exactly the set of modeled fields for that type.
701*5f757f3fSDimitry Andric     // `ModeledFields` includes fields from all the bases, but only the
702*5f757f3fSDimitry Andric     // modeled ones. However, if a class type is initialized with an
703*5f757f3fSDimitry Andric     // `InitListExpr`, all fields in the class, including those from base
704*5f757f3fSDimitry Andric     // classes, are included in the set of modeled fields. The code above
705*5f757f3fSDimitry Andric     // should therefore populate exactly the modeled fields.
706*5f757f3fSDimitry Andric     assert(containsSameFields(
707*5f757f3fSDimitry Andric         Env.getDataflowAnalysisContext().getModeledFields(Type), FieldLocs));
708*5f757f3fSDimitry Andric 
709*5f757f3fSDimitry Andric     RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs;
710*5f757f3fSDimitry Andric     for (const auto &Entry :
711*5f757f3fSDimitry Andric          Env.getDataflowAnalysisContext().getSyntheticFields(Type)) {
712*5f757f3fSDimitry Andric       SyntheticFieldLocs.insert(
713*5f757f3fSDimitry Andric           {Entry.getKey(), &Env.createObject(Entry.getValue())});
714*5f757f3fSDimitry Andric     }
715*5f757f3fSDimitry Andric 
716*5f757f3fSDimitry Andric     auto &Loc = Env.getDataflowAnalysisContext().createRecordStorageLocation(
717*5f757f3fSDimitry Andric         Type, std::move(FieldLocs), std::move(SyntheticFieldLocs));
718*5f757f3fSDimitry Andric     RecordValue &RecordVal = Env.create<RecordValue>(Loc);
719*5f757f3fSDimitry Andric 
720*5f757f3fSDimitry Andric     Env.setValue(Loc, RecordVal);
721*5f757f3fSDimitry Andric 
722*5f757f3fSDimitry Andric     Env.setValue(*S, RecordVal);
72306c3fb27SDimitry Andric 
72404eeddc0SDimitry Andric     // FIXME: Implement array initialization.
72504eeddc0SDimitry Andric   }
72604eeddc0SDimitry Andric 
72704eeddc0SDimitry Andric   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
728*5f757f3fSDimitry Andric     Env.setValue(*S, Env.getBoolLiteralValue(S->getValue()));
72906c3fb27SDimitry Andric   }
73006c3fb27SDimitry Andric 
73106c3fb27SDimitry Andric   void VisitIntegerLiteral(const IntegerLiteral *S) {
732*5f757f3fSDimitry Andric     Env.setValue(*S, Env.getIntLiteralValue(S->getValue()));
73304eeddc0SDimitry Andric   }
73404eeddc0SDimitry Andric 
73581ad6265SDimitry Andric   void VisitParenExpr(const ParenExpr *S) {
73681ad6265SDimitry Andric     // The CFG does not contain `ParenExpr` as top-level statements in basic
73781ad6265SDimitry Andric     // blocks, however manual traversal to sub-expressions may encounter them.
73881ad6265SDimitry Andric     // Redirect to the sub-expression.
73981ad6265SDimitry Andric     auto *SubExpr = S->getSubExpr();
74081ad6265SDimitry Andric     assert(SubExpr != nullptr);
74181ad6265SDimitry Andric     Visit(SubExpr);
74281ad6265SDimitry Andric   }
74381ad6265SDimitry Andric 
74481ad6265SDimitry Andric   void VisitExprWithCleanups(const ExprWithCleanups *S) {
74581ad6265SDimitry Andric     // The CFG does not contain `ExprWithCleanups` as top-level statements in
74681ad6265SDimitry Andric     // basic blocks, however manual traversal to sub-expressions may encounter
74781ad6265SDimitry Andric     // them. Redirect to the sub-expression.
74881ad6265SDimitry Andric     auto *SubExpr = S->getSubExpr();
74981ad6265SDimitry Andric     assert(SubExpr != nullptr);
75081ad6265SDimitry Andric     Visit(SubExpr);
75181ad6265SDimitry Andric   }
75281ad6265SDimitry Andric 
75304eeddc0SDimitry Andric private:
75406c3fb27SDimitry Andric   /// Returns the value for the sub-expression `SubExpr` of a logic operator.
75581ad6265SDimitry Andric   BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
75681ad6265SDimitry Andric     // `SubExpr` and its parent logic operator might be part of different basic
75781ad6265SDimitry Andric     // blocks. We try to access the value that is assigned to `SubExpr` in the
75881ad6265SDimitry Andric     // corresponding environment.
75906c3fb27SDimitry Andric     if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr))
76006c3fb27SDimitry Andric       if (auto *Val =
761*5f757f3fSDimitry Andric               dyn_cast_or_null<BoolValue>(SubExprEnv->getValue(SubExpr)))
76281ad6265SDimitry Andric         return *Val;
76381ad6265SDimitry Andric 
76406c3fb27SDimitry Andric     // The sub-expression may lie within a basic block that isn't reachable,
76506c3fb27SDimitry Andric     // even if we need it to evaluate the current (reachable) expression
76606c3fb27SDimitry Andric     // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr`
76706c3fb27SDimitry Andric     // within the current environment and then try to get the value that gets
76806c3fb27SDimitry Andric     // assigned to it.
769*5f757f3fSDimitry Andric     if (Env.getValue(SubExpr) == nullptr)
77081ad6265SDimitry Andric       Visit(&SubExpr);
771*5f757f3fSDimitry Andric     if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValue(SubExpr)))
77281ad6265SDimitry Andric       return *Val;
77381ad6265SDimitry Andric 
77481ad6265SDimitry Andric     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
77581ad6265SDimitry Andric     // boolean value for it.
77681ad6265SDimitry Andric     return Env.makeAtomicBoolValue();
77781ad6265SDimitry Andric   }
77881ad6265SDimitry Andric 
779bdd1243dSDimitry Andric   // If context sensitivity is enabled, try to analyze the body of the callee
780bdd1243dSDimitry Andric   // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`.
781bdd1243dSDimitry Andric   template <typename E>
782bdd1243dSDimitry Andric   void transferInlineCall(const E *S, const FunctionDecl *F) {
78306c3fb27SDimitry Andric     const auto &Options = Env.getDataflowAnalysisContext().getOptions();
784bdd1243dSDimitry Andric     if (!(Options.ContextSensitiveOpts &&
785bdd1243dSDimitry Andric           Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))
786bdd1243dSDimitry Andric       return;
787bdd1243dSDimitry Andric 
78806c3fb27SDimitry Andric     const ControlFlowContext *CFCtx =
78906c3fb27SDimitry Andric         Env.getDataflowAnalysisContext().getControlFlowContext(F);
790bdd1243dSDimitry Andric     if (!CFCtx)
791bdd1243dSDimitry Andric       return;
792bdd1243dSDimitry Andric 
793bdd1243dSDimitry Andric     // FIXME: We don't support context-sensitive analysis of recursion, so
794bdd1243dSDimitry Andric     // we should return early here if `F` is the same as the `FunctionDecl`
795bdd1243dSDimitry Andric     // holding `S` itself.
796bdd1243dSDimitry Andric 
797bdd1243dSDimitry Andric     auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
798bdd1243dSDimitry Andric 
799bdd1243dSDimitry Andric     auto CalleeEnv = Env.pushCall(S);
800bdd1243dSDimitry Andric 
801bdd1243dSDimitry Andric     // FIXME: Use the same analysis as the caller for the callee. Note,
802bdd1243dSDimitry Andric     // though, that doing so would require support for changing the analysis's
803bdd1243dSDimitry Andric     // ASTContext.
804*5f757f3fSDimitry Andric     auto Analysis = NoopAnalysis(CFCtx->getDecl().getASTContext(),
805bdd1243dSDimitry Andric                                  DataflowAnalysisOptions{Options});
806bdd1243dSDimitry Andric 
807bdd1243dSDimitry Andric     auto BlockToOutputState =
808bdd1243dSDimitry Andric         dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
809bdd1243dSDimitry Andric     assert(BlockToOutputState);
810bdd1243dSDimitry Andric     assert(ExitBlock < BlockToOutputState->size());
811bdd1243dSDimitry Andric 
81206c3fb27SDimitry Andric     auto &ExitState = (*BlockToOutputState)[ExitBlock];
813bdd1243dSDimitry Andric     assert(ExitState);
814bdd1243dSDimitry Andric 
81506c3fb27SDimitry Andric     Env.popCall(S, ExitState->Env);
816bdd1243dSDimitry Andric   }
817bdd1243dSDimitry Andric 
81881ad6265SDimitry Andric   const StmtToEnvMap &StmtToEnv;
81904eeddc0SDimitry Andric   Environment &Env;
82004eeddc0SDimitry Andric };
82104eeddc0SDimitry Andric 
82206c3fb27SDimitry Andric } // namespace
82306c3fb27SDimitry Andric 
824bdd1243dSDimitry Andric void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
825bdd1243dSDimitry Andric   TransferVisitor(StmtToEnv, Env).Visit(&S);
82604eeddc0SDimitry Andric }
82704eeddc0SDimitry Andric 
82804eeddc0SDimitry Andric } // namespace dataflow
82904eeddc0SDimitry Andric } // namespace clang
830