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" 315f757f3fSDimitry Andric #include "llvm/Support/Debug.h" 325f757f3fSDimitry Andric #include <assert.h> 3304eeddc0SDimitry Andric #include <cassert> 345f757f3fSDimitry Andric 355f757f3fSDimitry 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()]; 465f757f3fSDimitry Andric if (!(State)) 475f757f3fSDimitry 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) { 535f757f3fSDimitry Andric Value *LHSValue = Env.getValue(LHS); 545f757f3fSDimitry 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) { 785f757f3fSDimitry 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) { 955f757f3fSDimitry Andric if (auto *Val = Env.getValue(From)) 965f757f3fSDimitry Andric Env.setValue(To, *Val); 9706c3fb27SDimitry Andric } 9806c3fb27SDimitry Andric 9906c3fb27SDimitry Andric static void propagateStorageLocation(const Expr &From, const Expr &To, 10006c3fb27SDimitry Andric Environment &Env) { 1015f757f3fSDimitry Andric if (auto *Loc = Env.getStorageLocation(From)) 1025f757f3fSDimitry 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: { 1335f757f3fSDimitry Andric auto *LHSLoc = Env.getStorageLocation(*LHS); 13404eeddc0SDimitry Andric if (LHSLoc == nullptr) 13581ad6265SDimitry Andric break; 13604eeddc0SDimitry Andric 1375f757f3fSDimitry 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) 1545f757f3fSDimitry Andric Env.setValue(*S, Env.makeAnd(LHSVal, RHSVal)); 15581ad6265SDimitry Andric else 1565f757f3fSDimitry 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); 1625f757f3fSDimitry 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 1795f757f3fSDimitry Andric // Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a 1805f757f3fSDimitry Andric // `StorageLocation`, and there's also no sensible `Value` that we can 1815f757f3fSDimitry Andric // assign to them. Examples: 1825f757f3fSDimitry Andric // - Non-static member variables 1835f757f3fSDimitry Andric // - Non static member functions 1845f757f3fSDimitry Andric // Note: Member operators are an exception to this, but apparently only 1855f757f3fSDimitry Andric // if the `DeclRefExpr` is used within the callee of a 1865f757f3fSDimitry Andric // `CXXOperatorCallExpr`. In other cases, for example when applying the 1875f757f3fSDimitry Andric // address-of operator, the `DeclRefExpr` is a prvalue. 1885f757f3fSDimitry 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 1955f757f3fSDimitry 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 2415f757f3fSDimitry 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 = 2695f757f3fSDimitry Andric dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr))) 2705f757f3fSDimitry 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. 2745f757f3fSDimitry 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 2805f757f3fSDimitry 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 2855f757f3fSDimitry 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()); 3105f757f3fSDimitry 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: { 3185f757f3fSDimitry Andric StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr); 31906c3fb27SDimitry Andric if (PointeeLoc == nullptr) 32006c3fb27SDimitry Andric break; 32106c3fb27SDimitry Andric 3225f757f3fSDimitry 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: { 342*cb14a3feSDimitry Andric const auto *SubExprVal = Env.get<PointerValue>(*SubExpr); 34304eeddc0SDimitry Andric if (SubExprVal == nullptr) 34404eeddc0SDimitry Andric break; 34504eeddc0SDimitry Andric 3465f757f3fSDimitry Andric Env.setStorageLocation(*S, SubExprVal->getPointeeLoc()); 34704eeddc0SDimitry Andric break; 34804eeddc0SDimitry Andric } 34904eeddc0SDimitry Andric case UO_AddrOf: { 35006c3fb27SDimitry Andric // FIXME: Model pointers to members. 35106c3fb27SDimitry Andric if (S->getType()->isMemberPointerType()) 35204eeddc0SDimitry Andric break; 35304eeddc0SDimitry Andric 3545f757f3fSDimitry Andric if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr)) 3555f757f3fSDimitry Andric Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc)); 35604eeddc0SDimitry Andric break; 35704eeddc0SDimitry Andric } 35881ad6265SDimitry Andric case UO_LNot: { 3595f757f3fSDimitry Andric auto *SubExprVal = dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr)); 36081ad6265SDimitry Andric if (SubExprVal == nullptr) 36181ad6265SDimitry Andric break; 36281ad6265SDimitry Andric 3635f757f3fSDimitry Andric Env.setValue(*S, Env.makeNot(*SubExprVal)); 36481ad6265SDimitry Andric break; 36581ad6265SDimitry Andric } 36604eeddc0SDimitry Andric default: 36704eeddc0SDimitry Andric break; 36804eeddc0SDimitry Andric } 36904eeddc0SDimitry Andric } 37004eeddc0SDimitry Andric 37104eeddc0SDimitry Andric void VisitCXXThisExpr(const CXXThisExpr *S) { 37204eeddc0SDimitry Andric auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); 37381ad6265SDimitry Andric if (ThisPointeeLoc == nullptr) 37481ad6265SDimitry Andric // Unions are not supported yet, and will not have a location for the 37581ad6265SDimitry Andric // `this` expression's pointee. 37681ad6265SDimitry Andric return; 37704eeddc0SDimitry Andric 3785f757f3fSDimitry Andric Env.setValue(*S, Env.create<PointerValue>(*ThisPointeeLoc)); 37906c3fb27SDimitry Andric } 38006c3fb27SDimitry Andric 38106c3fb27SDimitry Andric void VisitCXXNewExpr(const CXXNewExpr *S) { 38206c3fb27SDimitry Andric if (Value *Val = Env.createValue(S->getType())) 3835f757f3fSDimitry Andric Env.setValue(*S, *Val); 38406c3fb27SDimitry Andric } 38506c3fb27SDimitry Andric 38606c3fb27SDimitry Andric void VisitCXXDeleteExpr(const CXXDeleteExpr *S) { 38706c3fb27SDimitry Andric // Empty method. 38806c3fb27SDimitry Andric // We consciously don't do anything on deletes. Diagnosing double deletes 38906c3fb27SDimitry Andric // (for example) should be done by a specific analysis, not by the 39006c3fb27SDimitry Andric // framework. 39104eeddc0SDimitry Andric } 39204eeddc0SDimitry Andric 393bdd1243dSDimitry Andric void VisitReturnStmt(const ReturnStmt *S) { 39406c3fb27SDimitry Andric if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts) 395bdd1243dSDimitry Andric return; 396bdd1243dSDimitry Andric 397bdd1243dSDimitry Andric auto *Ret = S->getRetValue(); 398bdd1243dSDimitry Andric if (Ret == nullptr) 399bdd1243dSDimitry Andric return; 400bdd1243dSDimitry Andric 40106c3fb27SDimitry Andric if (Ret->isPRValue()) { 4025f757f3fSDimitry Andric auto *Val = Env.getValue(*Ret); 403bdd1243dSDimitry Andric if (Val == nullptr) 404bdd1243dSDimitry Andric return; 405bdd1243dSDimitry Andric 40606c3fb27SDimitry Andric // FIXME: Model NRVO. 40706c3fb27SDimitry Andric Env.setReturnValue(Val); 40806c3fb27SDimitry Andric } else { 4095f757f3fSDimitry Andric auto *Loc = Env.getStorageLocation(*Ret); 41006c3fb27SDimitry Andric if (Loc == nullptr) 411bdd1243dSDimitry Andric return; 412bdd1243dSDimitry Andric 413bdd1243dSDimitry Andric // FIXME: Model NRVO. 41406c3fb27SDimitry Andric Env.setReturnStorageLocation(Loc); 41506c3fb27SDimitry Andric } 416bdd1243dSDimitry Andric } 417bdd1243dSDimitry Andric 41804eeddc0SDimitry Andric void VisitMemberExpr(const MemberExpr *S) { 41904eeddc0SDimitry Andric ValueDecl *Member = S->getMemberDecl(); 42004eeddc0SDimitry Andric assert(Member != nullptr); 42104eeddc0SDimitry Andric 42204eeddc0SDimitry Andric // FIXME: Consider assigning pointer values to function member expressions. 42304eeddc0SDimitry Andric if (Member->isFunctionOrFunctionTemplate()) 42404eeddc0SDimitry Andric return; 42504eeddc0SDimitry Andric 426bdd1243dSDimitry Andric // FIXME: if/when we add support for modeling enums, use that support here. 427bdd1243dSDimitry Andric if (isa<EnumConstantDecl>(Member)) 428bdd1243dSDimitry Andric return; 429bdd1243dSDimitry Andric 43081ad6265SDimitry Andric if (auto *D = dyn_cast<VarDecl>(Member)) { 43181ad6265SDimitry Andric if (D->hasGlobalStorage()) { 43206c3fb27SDimitry Andric auto *VarDeclLoc = Env.getStorageLocation(*D); 43381ad6265SDimitry Andric if (VarDeclLoc == nullptr) 43481ad6265SDimitry Andric return; 43581ad6265SDimitry Andric 43681ad6265SDimitry Andric Env.setStorageLocation(*S, *VarDeclLoc); 43781ad6265SDimitry Andric return; 43881ad6265SDimitry Andric } 43981ad6265SDimitry Andric } 44081ad6265SDimitry Andric 4415f757f3fSDimitry Andric RecordStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env); 44204eeddc0SDimitry Andric if (BaseLoc == nullptr) 44304eeddc0SDimitry Andric return; 44404eeddc0SDimitry Andric 44506c3fb27SDimitry Andric auto *MemberLoc = BaseLoc->getChild(*Member); 44606c3fb27SDimitry Andric if (MemberLoc == nullptr) 44706c3fb27SDimitry Andric return; 4485f757f3fSDimitry Andric Env.setStorageLocation(*S, *MemberLoc); 44904eeddc0SDimitry Andric } 45004eeddc0SDimitry Andric 45104eeddc0SDimitry Andric void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { 45204eeddc0SDimitry Andric const Expr *InitExpr = S->getExpr(); 45304eeddc0SDimitry Andric assert(InitExpr != nullptr); 45406c3fb27SDimitry Andric propagateValueOrStorageLocation(*InitExpr, *S, Env); 45504eeddc0SDimitry Andric } 45604eeddc0SDimitry Andric 45704eeddc0SDimitry Andric void VisitCXXConstructExpr(const CXXConstructExpr *S) { 45804eeddc0SDimitry Andric const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); 45904eeddc0SDimitry Andric assert(ConstructorDecl != nullptr); 46004eeddc0SDimitry Andric 46104eeddc0SDimitry Andric if (ConstructorDecl->isCopyOrMoveConstructor()) { 46206c3fb27SDimitry Andric // It is permissible for a copy/move constructor to have additional 46306c3fb27SDimitry Andric // parameters as long as they have default arguments defined for them. 46406c3fb27SDimitry Andric assert(S->getNumArgs() != 0); 46504eeddc0SDimitry Andric 46604eeddc0SDimitry Andric const Expr *Arg = S->getArg(0); 46704eeddc0SDimitry Andric assert(Arg != nullptr); 46804eeddc0SDimitry Andric 469*cb14a3feSDimitry Andric auto *ArgLoc = Env.get<RecordStorageLocation>(*Arg); 47004eeddc0SDimitry Andric if (ArgLoc == nullptr) 47104eeddc0SDimitry Andric return; 47204eeddc0SDimitry Andric 47306c3fb27SDimitry Andric if (S->isElidable()) { 4745f757f3fSDimitry Andric if (Value *Val = Env.getValue(*ArgLoc)) 4755f757f3fSDimitry Andric Env.setValue(*S, *Val); 4765f757f3fSDimitry Andric } else { 4775f757f3fSDimitry Andric auto &Val = *cast<RecordValue>(Env.createValue(S->getType())); 4785f757f3fSDimitry Andric Env.setValue(*S, Val); 4795f757f3fSDimitry Andric copyRecord(*ArgLoc, Val.getLoc(), Env); 48004eeddc0SDimitry Andric } 48104eeddc0SDimitry Andric return; 48204eeddc0SDimitry Andric } 48304eeddc0SDimitry Andric 4845f757f3fSDimitry Andric // `CXXConstructExpr` can have array type if default-initializing an array 4855f757f3fSDimitry Andric // of records, and we currently can't create values for arrays. So check if 4865f757f3fSDimitry Andric // we've got a record type. 4875f757f3fSDimitry Andric if (S->getType()->isRecordType()) { 4885f757f3fSDimitry Andric auto &InitialVal = *cast<RecordValue>(Env.createValue(S->getType())); 4895f757f3fSDimitry Andric Env.setValue(*S, InitialVal); 4905f757f3fSDimitry Andric } 491bdd1243dSDimitry Andric 492bdd1243dSDimitry Andric transferInlineCall(S, ConstructorDecl); 49304eeddc0SDimitry Andric } 49404eeddc0SDimitry Andric 49504eeddc0SDimitry Andric void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { 49604eeddc0SDimitry Andric if (S->getOperator() == OO_Equal) { 49704eeddc0SDimitry Andric assert(S->getNumArgs() == 2); 49804eeddc0SDimitry Andric 49904eeddc0SDimitry Andric const Expr *Arg0 = S->getArg(0); 50004eeddc0SDimitry Andric assert(Arg0 != nullptr); 50104eeddc0SDimitry Andric 50204eeddc0SDimitry Andric const Expr *Arg1 = S->getArg(1); 50304eeddc0SDimitry Andric assert(Arg1 != nullptr); 50404eeddc0SDimitry Andric 50504eeddc0SDimitry Andric // Evaluate only copy and move assignment operators. 50606c3fb27SDimitry Andric const auto *Method = 50706c3fb27SDimitry Andric dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee()); 50806c3fb27SDimitry Andric if (!Method) 50906c3fb27SDimitry Andric return; 51006c3fb27SDimitry Andric if (!Method->isCopyAssignmentOperator() && 51106c3fb27SDimitry Andric !Method->isMoveAssignmentOperator()) 51204eeddc0SDimitry Andric return; 51304eeddc0SDimitry Andric 5145f757f3fSDimitry Andric RecordStorageLocation *LocSrc = nullptr; 5155f757f3fSDimitry Andric if (Arg1->isPRValue()) { 516*cb14a3feSDimitry Andric if (auto *Val = Env.get<RecordValue>(*Arg1)) 5175f757f3fSDimitry Andric LocSrc = &Val->getLoc(); 5185f757f3fSDimitry Andric } else { 519*cb14a3feSDimitry Andric LocSrc = Env.get<RecordStorageLocation>(*Arg1); 52006c3fb27SDimitry Andric } 521*cb14a3feSDimitry Andric auto *LocDst = Env.get<RecordStorageLocation>(*Arg0); 5225f757f3fSDimitry Andric 5235f757f3fSDimitry Andric if (LocSrc == nullptr || LocDst == nullptr) 5245f757f3fSDimitry Andric return; 5255f757f3fSDimitry Andric 5265f757f3fSDimitry Andric // The assignment operators are different from the type of the destination 5275f757f3fSDimitry Andric // in this model (i.e. in one of their base classes). This must be very 5285f757f3fSDimitry Andric // rare and we just bail. 5295f757f3fSDimitry Andric if (Method->getFunctionObjectParameterType() 5305f757f3fSDimitry Andric .getCanonicalType() 5315f757f3fSDimitry Andric .getUnqualifiedType() != 5325f757f3fSDimitry Andric LocDst->getType().getCanonicalType().getUnqualifiedType()) 5335f757f3fSDimitry Andric return; 5345f757f3fSDimitry Andric 5355f757f3fSDimitry Andric copyRecord(*LocSrc, *LocDst, Env); 5365f757f3fSDimitry Andric Env.setStorageLocation(*S, *LocDst); 53704eeddc0SDimitry Andric } 53804eeddc0SDimitry Andric } 53904eeddc0SDimitry Andric 54004eeddc0SDimitry Andric void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { 54104eeddc0SDimitry Andric if (S->getCastKind() == CK_ConstructorConversion) { 54204eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 54304eeddc0SDimitry Andric assert(SubExpr != nullptr); 54404eeddc0SDimitry Andric 54506c3fb27SDimitry Andric propagateValue(*SubExpr, *S, Env); 54604eeddc0SDimitry Andric } 54704eeddc0SDimitry Andric } 54804eeddc0SDimitry Andric 54904eeddc0SDimitry Andric void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { 55004eeddc0SDimitry Andric if (Value *Val = Env.createValue(S->getType())) 5515f757f3fSDimitry Andric Env.setValue(*S, *Val); 55204eeddc0SDimitry Andric } 55304eeddc0SDimitry Andric 55404eeddc0SDimitry Andric void VisitCallExpr(const CallExpr *S) { 55581ad6265SDimitry Andric // Of clang's builtins, only `__builtin_expect` is handled explicitly, since 55681ad6265SDimitry Andric // others (like trap, debugtrap, and unreachable) are handled by CFG 55781ad6265SDimitry Andric // construction. 55804eeddc0SDimitry Andric if (S->isCallToStdMove()) { 55904eeddc0SDimitry Andric assert(S->getNumArgs() == 1); 56004eeddc0SDimitry Andric 56104eeddc0SDimitry Andric const Expr *Arg = S->getArg(0); 56204eeddc0SDimitry Andric assert(Arg != nullptr); 56304eeddc0SDimitry Andric 5645f757f3fSDimitry Andric auto *ArgLoc = Env.getStorageLocation(*Arg); 56504eeddc0SDimitry Andric if (ArgLoc == nullptr) 56604eeddc0SDimitry Andric return; 56704eeddc0SDimitry Andric 56804eeddc0SDimitry Andric Env.setStorageLocation(*S, *ArgLoc); 56981ad6265SDimitry Andric } else if (S->getDirectCallee() != nullptr && 57081ad6265SDimitry Andric S->getDirectCallee()->getBuiltinID() == 57181ad6265SDimitry Andric Builtin::BI__builtin_expect) { 57281ad6265SDimitry Andric assert(S->getNumArgs() > 0); 57381ad6265SDimitry Andric assert(S->getArg(0) != nullptr); 5745f757f3fSDimitry Andric auto *ArgVal = Env.getValue(*S->getArg(0)); 5755f757f3fSDimitry Andric if (ArgVal == nullptr) 57681ad6265SDimitry Andric return; 5775f757f3fSDimitry Andric Env.setValue(*S, *ArgVal); 578972a253aSDimitry Andric } else if (const FunctionDecl *F = S->getDirectCallee()) { 579bdd1243dSDimitry Andric transferInlineCall(S, F); 580*cb14a3feSDimitry Andric 581*cb14a3feSDimitry Andric // If this call produces a prvalue of record type, make sure that we have 582*cb14a3feSDimitry Andric // a `RecordValue` for it. This is required so that 583*cb14a3feSDimitry Andric // `Environment::getResultObjectLocation()` is able to return a location 584*cb14a3feSDimitry Andric // for this `CallExpr`. 585*cb14a3feSDimitry Andric if (S->getType()->isRecordType() && S->isPRValue()) 586*cb14a3feSDimitry Andric if (Env.getValue(*S) == nullptr) 587*cb14a3feSDimitry Andric refreshRecordValue(*S, Env); 58804eeddc0SDimitry Andric } 58904eeddc0SDimitry Andric } 59004eeddc0SDimitry Andric 59104eeddc0SDimitry Andric void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { 59204eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 59304eeddc0SDimitry Andric assert(SubExpr != nullptr); 59404eeddc0SDimitry Andric 5955f757f3fSDimitry Andric Value *SubExprVal = Env.getValue(*SubExpr); 59606c3fb27SDimitry Andric if (SubExprVal == nullptr) 59704eeddc0SDimitry Andric return; 59804eeddc0SDimitry Andric 5995f757f3fSDimitry Andric if (RecordValue *RecordVal = dyn_cast<RecordValue>(SubExprVal)) { 6005f757f3fSDimitry Andric Env.setStorageLocation(*S, RecordVal->getLoc()); 60106c3fb27SDimitry Andric return; 60206c3fb27SDimitry Andric } 60306c3fb27SDimitry Andric 60406c3fb27SDimitry Andric StorageLocation &Loc = Env.createStorageLocation(*S); 60506c3fb27SDimitry Andric Env.setValue(Loc, *SubExprVal); 60606c3fb27SDimitry Andric Env.setStorageLocation(*S, Loc); 60704eeddc0SDimitry Andric } 60804eeddc0SDimitry Andric 60904eeddc0SDimitry Andric void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { 61004eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 61104eeddc0SDimitry Andric assert(SubExpr != nullptr); 61204eeddc0SDimitry Andric 61306c3fb27SDimitry Andric propagateValue(*SubExpr, *S, Env); 61404eeddc0SDimitry Andric } 61504eeddc0SDimitry Andric 61604eeddc0SDimitry Andric void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { 61704eeddc0SDimitry Andric if (S->getCastKind() == CK_NoOp) { 61804eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 61904eeddc0SDimitry Andric assert(SubExpr != nullptr); 62004eeddc0SDimitry Andric 62106c3fb27SDimitry Andric propagateValueOrStorageLocation(*SubExpr, *S, Env); 62204eeddc0SDimitry Andric } 62304eeddc0SDimitry Andric } 62404eeddc0SDimitry Andric 62504eeddc0SDimitry Andric void VisitConditionalOperator(const ConditionalOperator *S) { 62604eeddc0SDimitry Andric // FIXME: Revisit this once flow conditions are added to the framework. For 62704eeddc0SDimitry Andric // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow 62804eeddc0SDimitry Andric // condition. 6295f757f3fSDimitry Andric // When we do this, we will need to retrieve the values of the operands from 6305f757f3fSDimitry Andric // the environments for the basic blocks they are computed in, in a similar 6315f757f3fSDimitry Andric // way to how this is done for short-circuited logical operators in 6325f757f3fSDimitry Andric // `getLogicOperatorSubExprValue()`. 63306c3fb27SDimitry Andric if (S->isGLValue()) 6345f757f3fSDimitry Andric Env.setStorageLocation(*S, Env.createObject(S->getType())); 63506c3fb27SDimitry Andric else if (Value *Val = Env.createValue(S->getType())) 6365f757f3fSDimitry Andric Env.setValue(*S, *Val); 63704eeddc0SDimitry Andric } 63804eeddc0SDimitry Andric 63904eeddc0SDimitry Andric void VisitInitListExpr(const InitListExpr *S) { 64004eeddc0SDimitry Andric QualType Type = S->getType(); 64104eeddc0SDimitry Andric 64206c3fb27SDimitry Andric if (!Type->isStructureOrClassType()) { 64306c3fb27SDimitry Andric if (auto *Val = Env.createValue(Type)) 6445f757f3fSDimitry Andric Env.setValue(*S, *Val); 64504eeddc0SDimitry Andric 64604eeddc0SDimitry Andric return; 64706c3fb27SDimitry Andric } 64804eeddc0SDimitry Andric 6495f757f3fSDimitry Andric // In case the initializer list is transparent, we just need to propagate 6505f757f3fSDimitry Andric // the value that it contains. 6515f757f3fSDimitry Andric if (S->isSemanticForm() && S->isTransparent()) { 6525f757f3fSDimitry Andric propagateValue(*S->getInit(0), *S, Env); 6535f757f3fSDimitry Andric return; 65404eeddc0SDimitry Andric } 65506c3fb27SDimitry Andric 6565f757f3fSDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 65706c3fb27SDimitry Andric 6585f757f3fSDimitry Andric // This only contains the direct fields for the given type. 6595f757f3fSDimitry Andric std::vector<FieldDecl *> FieldsForInit = 6605f757f3fSDimitry Andric getFieldsForInitListExpr(Type->getAsRecordDecl()); 66106c3fb27SDimitry Andric 6625f757f3fSDimitry Andric // `S->inits()` contains all the initializer epressions, including the 6635f757f3fSDimitry Andric // ones for direct base classes. 6645f757f3fSDimitry Andric auto Inits = S->inits(); 6655f757f3fSDimitry Andric size_t InitIdx = 0; 6665f757f3fSDimitry Andric 6675f757f3fSDimitry Andric // Initialize base classes. 6685f757f3fSDimitry Andric if (auto* R = S->getType()->getAsCXXRecordDecl()) { 6695f757f3fSDimitry Andric assert(FieldsForInit.size() + R->getNumBases() == Inits.size()); 6705f757f3fSDimitry Andric for ([[maybe_unused]] const CXXBaseSpecifier &Base : R->bases()) { 6715f757f3fSDimitry Andric assert(InitIdx < Inits.size()); 6725f757f3fSDimitry Andric auto Init = Inits[InitIdx++]; 6735f757f3fSDimitry Andric assert(Base.getType().getCanonicalType() == 6745f757f3fSDimitry Andric Init->getType().getCanonicalType()); 675*cb14a3feSDimitry Andric auto *BaseVal = Env.get<RecordValue>(*Init); 6765f757f3fSDimitry Andric if (!BaseVal) 6775f757f3fSDimitry Andric BaseVal = cast<RecordValue>(Env.createValue(Init->getType())); 6785f757f3fSDimitry Andric // Take ownership of the fields of the `RecordValue` for the base class 6795f757f3fSDimitry Andric // and incorporate them into the "flattened" set of fields for the 6805f757f3fSDimitry Andric // derived class. 6815f757f3fSDimitry Andric auto Children = BaseVal->getLoc().children(); 6825f757f3fSDimitry Andric FieldLocs.insert(Children.begin(), Children.end()); 6835f757f3fSDimitry Andric } 6845f757f3fSDimitry Andric } 6855f757f3fSDimitry Andric 6865f757f3fSDimitry Andric assert(FieldsForInit.size() == Inits.size() - InitIdx); 6875f757f3fSDimitry Andric for (auto Field : FieldsForInit) { 6885f757f3fSDimitry Andric assert(InitIdx < Inits.size()); 6895f757f3fSDimitry Andric auto Init = Inits[InitIdx++]; 6905f757f3fSDimitry Andric assert( 6915f757f3fSDimitry Andric // The types are same, or 6925f757f3fSDimitry Andric Field->getType().getCanonicalType().getUnqualifiedType() == 6935f757f3fSDimitry Andric Init->getType().getCanonicalType().getUnqualifiedType() || 6945f757f3fSDimitry Andric // The field's type is T&, and initializer is T 6955f757f3fSDimitry Andric (Field->getType()->isReferenceType() && 6965f757f3fSDimitry Andric Field->getType().getCanonicalType()->getPointeeType() == 6975f757f3fSDimitry Andric Init->getType().getCanonicalType())); 6985f757f3fSDimitry Andric auto& Loc = Env.createObject(Field->getType(), Init); 6995f757f3fSDimitry Andric FieldLocs.insert({Field, &Loc}); 7005f757f3fSDimitry Andric } 7015f757f3fSDimitry Andric 7025f757f3fSDimitry Andric // Check that we satisfy the invariant that a `RecordStorageLoation` 7035f757f3fSDimitry Andric // contains exactly the set of modeled fields for that type. 7045f757f3fSDimitry Andric // `ModeledFields` includes fields from all the bases, but only the 7055f757f3fSDimitry Andric // modeled ones. However, if a class type is initialized with an 7065f757f3fSDimitry Andric // `InitListExpr`, all fields in the class, including those from base 7075f757f3fSDimitry Andric // classes, are included in the set of modeled fields. The code above 7085f757f3fSDimitry Andric // should therefore populate exactly the modeled fields. 7095f757f3fSDimitry Andric assert(containsSameFields( 7105f757f3fSDimitry Andric Env.getDataflowAnalysisContext().getModeledFields(Type), FieldLocs)); 7115f757f3fSDimitry Andric 7125f757f3fSDimitry Andric RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs; 7135f757f3fSDimitry Andric for (const auto &Entry : 7145f757f3fSDimitry Andric Env.getDataflowAnalysisContext().getSyntheticFields(Type)) { 7155f757f3fSDimitry Andric SyntheticFieldLocs.insert( 7165f757f3fSDimitry Andric {Entry.getKey(), &Env.createObject(Entry.getValue())}); 7175f757f3fSDimitry Andric } 7185f757f3fSDimitry Andric 7195f757f3fSDimitry Andric auto &Loc = Env.getDataflowAnalysisContext().createRecordStorageLocation( 7205f757f3fSDimitry Andric Type, std::move(FieldLocs), std::move(SyntheticFieldLocs)); 7215f757f3fSDimitry Andric RecordValue &RecordVal = Env.create<RecordValue>(Loc); 7225f757f3fSDimitry Andric 7235f757f3fSDimitry Andric Env.setValue(Loc, RecordVal); 7245f757f3fSDimitry Andric 7255f757f3fSDimitry Andric Env.setValue(*S, RecordVal); 72606c3fb27SDimitry Andric 72704eeddc0SDimitry Andric // FIXME: Implement array initialization. 72804eeddc0SDimitry Andric } 72904eeddc0SDimitry Andric 73004eeddc0SDimitry Andric void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { 7315f757f3fSDimitry Andric Env.setValue(*S, Env.getBoolLiteralValue(S->getValue())); 73206c3fb27SDimitry Andric } 73306c3fb27SDimitry Andric 73406c3fb27SDimitry Andric void VisitIntegerLiteral(const IntegerLiteral *S) { 7355f757f3fSDimitry Andric Env.setValue(*S, Env.getIntLiteralValue(S->getValue())); 73604eeddc0SDimitry Andric } 73704eeddc0SDimitry Andric 73881ad6265SDimitry Andric void VisitParenExpr(const ParenExpr *S) { 73981ad6265SDimitry Andric // The CFG does not contain `ParenExpr` as top-level statements in basic 74081ad6265SDimitry Andric // blocks, however manual traversal to sub-expressions may encounter them. 74181ad6265SDimitry Andric // Redirect to the sub-expression. 74281ad6265SDimitry Andric auto *SubExpr = S->getSubExpr(); 74381ad6265SDimitry Andric assert(SubExpr != nullptr); 74481ad6265SDimitry Andric Visit(SubExpr); 74581ad6265SDimitry Andric } 74681ad6265SDimitry Andric 74781ad6265SDimitry Andric void VisitExprWithCleanups(const ExprWithCleanups *S) { 74881ad6265SDimitry Andric // The CFG does not contain `ExprWithCleanups` as top-level statements in 74981ad6265SDimitry Andric // basic blocks, however manual traversal to sub-expressions may encounter 75081ad6265SDimitry Andric // them. Redirect to the sub-expression. 75181ad6265SDimitry Andric auto *SubExpr = S->getSubExpr(); 75281ad6265SDimitry Andric assert(SubExpr != nullptr); 75381ad6265SDimitry Andric Visit(SubExpr); 75481ad6265SDimitry Andric } 75581ad6265SDimitry Andric 75604eeddc0SDimitry Andric private: 75706c3fb27SDimitry Andric /// Returns the value for the sub-expression `SubExpr` of a logic operator. 75881ad6265SDimitry Andric BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { 75981ad6265SDimitry Andric // `SubExpr` and its parent logic operator might be part of different basic 76081ad6265SDimitry Andric // blocks. We try to access the value that is assigned to `SubExpr` in the 76181ad6265SDimitry Andric // corresponding environment. 76206c3fb27SDimitry Andric if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) 76306c3fb27SDimitry Andric if (auto *Val = 7645f757f3fSDimitry Andric dyn_cast_or_null<BoolValue>(SubExprEnv->getValue(SubExpr))) 76581ad6265SDimitry Andric return *Val; 76681ad6265SDimitry Andric 76706c3fb27SDimitry Andric // The sub-expression may lie within a basic block that isn't reachable, 76806c3fb27SDimitry Andric // even if we need it to evaluate the current (reachable) expression 76906c3fb27SDimitry Andric // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr` 77006c3fb27SDimitry Andric // within the current environment and then try to get the value that gets 77106c3fb27SDimitry Andric // assigned to it. 7725f757f3fSDimitry Andric if (Env.getValue(SubExpr) == nullptr) 77381ad6265SDimitry Andric Visit(&SubExpr); 7745f757f3fSDimitry Andric if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValue(SubExpr))) 77581ad6265SDimitry Andric return *Val; 77681ad6265SDimitry Andric 77781ad6265SDimitry Andric // If the value of `SubExpr` is still unknown, we create a fresh symbolic 77881ad6265SDimitry Andric // boolean value for it. 77981ad6265SDimitry Andric return Env.makeAtomicBoolValue(); 78081ad6265SDimitry Andric } 78181ad6265SDimitry Andric 782bdd1243dSDimitry Andric // If context sensitivity is enabled, try to analyze the body of the callee 783bdd1243dSDimitry Andric // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`. 784bdd1243dSDimitry Andric template <typename E> 785bdd1243dSDimitry Andric void transferInlineCall(const E *S, const FunctionDecl *F) { 78606c3fb27SDimitry Andric const auto &Options = Env.getDataflowAnalysisContext().getOptions(); 787bdd1243dSDimitry Andric if (!(Options.ContextSensitiveOpts && 788bdd1243dSDimitry Andric Env.canDescend(Options.ContextSensitiveOpts->Depth, F))) 789bdd1243dSDimitry Andric return; 790bdd1243dSDimitry Andric 79106c3fb27SDimitry Andric const ControlFlowContext *CFCtx = 79206c3fb27SDimitry Andric Env.getDataflowAnalysisContext().getControlFlowContext(F); 793bdd1243dSDimitry Andric if (!CFCtx) 794bdd1243dSDimitry Andric return; 795bdd1243dSDimitry Andric 796bdd1243dSDimitry Andric // FIXME: We don't support context-sensitive analysis of recursion, so 797bdd1243dSDimitry Andric // we should return early here if `F` is the same as the `FunctionDecl` 798bdd1243dSDimitry Andric // holding `S` itself. 799bdd1243dSDimitry Andric 800bdd1243dSDimitry Andric auto ExitBlock = CFCtx->getCFG().getExit().getBlockID(); 801bdd1243dSDimitry Andric 802bdd1243dSDimitry Andric auto CalleeEnv = Env.pushCall(S); 803bdd1243dSDimitry Andric 804bdd1243dSDimitry Andric // FIXME: Use the same analysis as the caller for the callee. Note, 805bdd1243dSDimitry Andric // though, that doing so would require support for changing the analysis's 806bdd1243dSDimitry Andric // ASTContext. 8075f757f3fSDimitry Andric auto Analysis = NoopAnalysis(CFCtx->getDecl().getASTContext(), 808bdd1243dSDimitry Andric DataflowAnalysisOptions{Options}); 809bdd1243dSDimitry Andric 810bdd1243dSDimitry Andric auto BlockToOutputState = 811bdd1243dSDimitry Andric dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv); 812bdd1243dSDimitry Andric assert(BlockToOutputState); 813bdd1243dSDimitry Andric assert(ExitBlock < BlockToOutputState->size()); 814bdd1243dSDimitry Andric 81506c3fb27SDimitry Andric auto &ExitState = (*BlockToOutputState)[ExitBlock]; 816bdd1243dSDimitry Andric assert(ExitState); 817bdd1243dSDimitry Andric 81806c3fb27SDimitry Andric Env.popCall(S, ExitState->Env); 819bdd1243dSDimitry Andric } 820bdd1243dSDimitry Andric 82181ad6265SDimitry Andric const StmtToEnvMap &StmtToEnv; 82204eeddc0SDimitry Andric Environment &Env; 82304eeddc0SDimitry Andric }; 82404eeddc0SDimitry Andric 82506c3fb27SDimitry Andric } // namespace 82606c3fb27SDimitry Andric 827bdd1243dSDimitry Andric void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { 828bdd1243dSDimitry Andric TransferVisitor(StmtToEnv, Env).Visit(&S); 82904eeddc0SDimitry Andric } 83004eeddc0SDimitry Andric 83104eeddc0SDimitry Andric } // namespace dataflow 83204eeddc0SDimitry Andric } // namespace clang 833