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; 45*7a6dacacSDimitry Andric if (BlockIt->getSecond()->getBlockID() == CurBlockID) 46*7a6dacacSDimitry Andric return &CurState.Env; 4706c3fb27SDimitry Andric const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()]; 485f757f3fSDimitry Andric if (!(State)) 495f757f3fSDimitry Andric return nullptr; 5006c3fb27SDimitry Andric return &State->Env; 5104eeddc0SDimitry Andric } 5204eeddc0SDimitry Andric 5306c3fb27SDimitry Andric static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, 5406c3fb27SDimitry Andric Environment &Env) { 555f757f3fSDimitry Andric Value *LHSValue = Env.getValue(LHS); 565f757f3fSDimitry Andric Value *RHSValue = Env.getValue(RHS); 57bdd1243dSDimitry Andric 5806c3fb27SDimitry Andric if (LHSValue == RHSValue) 5906c3fb27SDimitry Andric return Env.getBoolLiteralValue(true); 60bdd1243dSDimitry Andric 6106c3fb27SDimitry Andric if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue)) 6206c3fb27SDimitry Andric if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue)) 6306c3fb27SDimitry Andric return Env.makeIff(*LHSBool, *RHSBool); 64bdd1243dSDimitry Andric 6506c3fb27SDimitry Andric return Env.makeAtomicBoolValue(); 66bdd1243dSDimitry Andric } 67bdd1243dSDimitry Andric 68bdd1243dSDimitry Andric static BoolValue &unpackValue(BoolValue &V, Environment &Env) { 6906c3fb27SDimitry Andric if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) { 7006c3fb27SDimitry Andric auto &A = Env.getDataflowAnalysisContext().arena(); 7106c3fb27SDimitry Andric return A.makeBoolValue(A.makeAtomRef(Top->getAtom())); 72bdd1243dSDimitry Andric } 7306c3fb27SDimitry Andric return V; 74bdd1243dSDimitry Andric } 75bdd1243dSDimitry Andric 76bdd1243dSDimitry Andric // Unpacks the value (if any) associated with `E` and updates `E` to the new 7706c3fb27SDimitry Andric // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion, 7806c3fb27SDimitry Andric // by skipping past the reference. 79bdd1243dSDimitry Andric static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) { 805f757f3fSDimitry Andric auto *Loc = Env.getStorageLocation(E); 81bdd1243dSDimitry Andric if (Loc == nullptr) 82bdd1243dSDimitry Andric return nullptr; 83bdd1243dSDimitry Andric auto *Val = Env.getValue(*Loc); 84bdd1243dSDimitry Andric 85bdd1243dSDimitry Andric auto *B = dyn_cast_or_null<BoolValue>(Val); 86bdd1243dSDimitry Andric if (B == nullptr) 87bdd1243dSDimitry Andric return Val; 88bdd1243dSDimitry Andric 89bdd1243dSDimitry Andric auto &UnpackedVal = unpackValue(*B, Env); 90bdd1243dSDimitry Andric if (&UnpackedVal == Val) 91bdd1243dSDimitry Andric return Val; 92bdd1243dSDimitry Andric Env.setValue(*Loc, UnpackedVal); 93bdd1243dSDimitry Andric return &UnpackedVal; 94bdd1243dSDimitry Andric } 95bdd1243dSDimitry Andric 9606c3fb27SDimitry Andric static void propagateValue(const Expr &From, const Expr &To, Environment &Env) { 975f757f3fSDimitry Andric if (auto *Val = Env.getValue(From)) 985f757f3fSDimitry Andric Env.setValue(To, *Val); 9906c3fb27SDimitry Andric } 10006c3fb27SDimitry Andric 10106c3fb27SDimitry Andric static void propagateStorageLocation(const Expr &From, const Expr &To, 10206c3fb27SDimitry Andric Environment &Env) { 1035f757f3fSDimitry Andric if (auto *Loc = Env.getStorageLocation(From)) 1045f757f3fSDimitry Andric Env.setStorageLocation(To, *Loc); 10506c3fb27SDimitry Andric } 10606c3fb27SDimitry Andric 10706c3fb27SDimitry Andric // Propagates the value or storage location of `From` to `To` in cases where 10806c3fb27SDimitry Andric // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff 10906c3fb27SDimitry Andric // `From` is a glvalue. 11006c3fb27SDimitry Andric static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, 11106c3fb27SDimitry Andric Environment &Env) { 11206c3fb27SDimitry Andric assert(From.isGLValue() == To.isGLValue()); 11306c3fb27SDimitry Andric if (From.isGLValue()) 11406c3fb27SDimitry Andric propagateStorageLocation(From, To, Env); 11506c3fb27SDimitry Andric else 11606c3fb27SDimitry Andric propagateValue(From, To, Env); 11706c3fb27SDimitry Andric } 11806c3fb27SDimitry Andric 11906c3fb27SDimitry Andric namespace { 12006c3fb27SDimitry Andric 12104eeddc0SDimitry Andric class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { 12204eeddc0SDimitry Andric public: 123bdd1243dSDimitry Andric TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env) 124bdd1243dSDimitry Andric : StmtToEnv(StmtToEnv), Env(Env) {} 12504eeddc0SDimitry Andric 12604eeddc0SDimitry Andric void VisitBinaryOperator(const BinaryOperator *S) { 12781ad6265SDimitry Andric const Expr *LHS = S->getLHS(); 12804eeddc0SDimitry Andric assert(LHS != nullptr); 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric const Expr *RHS = S->getRHS(); 13181ad6265SDimitry Andric assert(RHS != nullptr); 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric switch (S->getOpcode()) { 13481ad6265SDimitry Andric case BO_Assign: { 1355f757f3fSDimitry Andric auto *LHSLoc = Env.getStorageLocation(*LHS); 13604eeddc0SDimitry Andric if (LHSLoc == nullptr) 13781ad6265SDimitry Andric break; 13804eeddc0SDimitry Andric 1395f757f3fSDimitry Andric auto *RHSVal = Env.getValue(*RHS); 14004eeddc0SDimitry Andric if (RHSVal == nullptr) 14181ad6265SDimitry Andric break; 14204eeddc0SDimitry Andric 14304eeddc0SDimitry Andric // Assign a value to the storage location of the left-hand side. 14404eeddc0SDimitry Andric Env.setValue(*LHSLoc, *RHSVal); 14504eeddc0SDimitry Andric 14604eeddc0SDimitry Andric // Assign a storage location for the whole expression. 14704eeddc0SDimitry Andric Env.setStorageLocation(*S, *LHSLoc); 14881ad6265SDimitry Andric break; 14904eeddc0SDimitry Andric } 15081ad6265SDimitry Andric case BO_LAnd: 15181ad6265SDimitry Andric case BO_LOr: { 15281ad6265SDimitry Andric BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS); 15381ad6265SDimitry Andric BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS); 15481ad6265SDimitry Andric 15581ad6265SDimitry Andric if (S->getOpcode() == BO_LAnd) 1565f757f3fSDimitry Andric Env.setValue(*S, Env.makeAnd(LHSVal, RHSVal)); 15781ad6265SDimitry Andric else 1585f757f3fSDimitry Andric Env.setValue(*S, Env.makeOr(LHSVal, RHSVal)); 15981ad6265SDimitry Andric break; 16081ad6265SDimitry Andric } 16181ad6265SDimitry Andric case BO_NE: 16281ad6265SDimitry Andric case BO_EQ: { 16381ad6265SDimitry Andric auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env); 1645f757f3fSDimitry Andric Env.setValue(*S, S->getOpcode() == BO_EQ ? LHSEqRHSValue 16581ad6265SDimitry Andric : Env.makeNot(LHSEqRHSValue)); 16681ad6265SDimitry Andric break; 16781ad6265SDimitry Andric } 16881ad6265SDimitry Andric case BO_Comma: { 16906c3fb27SDimitry Andric propagateValueOrStorageLocation(*RHS, *S, Env); 17081ad6265SDimitry Andric break; 17181ad6265SDimitry Andric } 17281ad6265SDimitry Andric default: 17381ad6265SDimitry Andric break; 17481ad6265SDimitry Andric } 17504eeddc0SDimitry Andric } 17604eeddc0SDimitry Andric 17704eeddc0SDimitry Andric void VisitDeclRefExpr(const DeclRefExpr *S) { 178bdd1243dSDimitry Andric const ValueDecl *VD = S->getDecl(); 179bdd1243dSDimitry Andric assert(VD != nullptr); 18006c3fb27SDimitry Andric 1815f757f3fSDimitry Andric // Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a 1825f757f3fSDimitry Andric // `StorageLocation`, and there's also no sensible `Value` that we can 1835f757f3fSDimitry Andric // assign to them. Examples: 1845f757f3fSDimitry Andric // - Non-static member variables 1855f757f3fSDimitry Andric // - Non static member functions 1865f757f3fSDimitry Andric // Note: Member operators are an exception to this, but apparently only 1875f757f3fSDimitry Andric // if the `DeclRefExpr` is used within the callee of a 1885f757f3fSDimitry Andric // `CXXOperatorCallExpr`. In other cases, for example when applying the 1895f757f3fSDimitry Andric // address-of operator, the `DeclRefExpr` is a prvalue. 1905f757f3fSDimitry Andric if (!S->isGLValue()) 19106c3fb27SDimitry Andric return; 19206c3fb27SDimitry Andric 19306c3fb27SDimitry Andric auto *DeclLoc = Env.getStorageLocation(*VD); 19404eeddc0SDimitry Andric if (DeclLoc == nullptr) 19504eeddc0SDimitry Andric return; 19604eeddc0SDimitry Andric 1975f757f3fSDimitry Andric Env.setStorageLocation(*S, *DeclLoc); 19804eeddc0SDimitry Andric } 19904eeddc0SDimitry Andric 20004eeddc0SDimitry Andric void VisitDeclStmt(const DeclStmt *S) { 20104eeddc0SDimitry Andric // Group decls are converted into single decls in the CFG so the cast below 20204eeddc0SDimitry Andric // is safe. 20304eeddc0SDimitry Andric const auto &D = *cast<VarDecl>(S->getSingleDecl()); 20481ad6265SDimitry Andric 20506c3fb27SDimitry Andric ProcessVarDecl(D); 20606c3fb27SDimitry Andric } 20706c3fb27SDimitry Andric 20806c3fb27SDimitry Andric void ProcessVarDecl(const VarDecl &D) { 20981ad6265SDimitry Andric // Static local vars are already initialized in `Environment`. 21081ad6265SDimitry Andric if (D.hasGlobalStorage()) 21181ad6265SDimitry Andric return; 21281ad6265SDimitry Andric 21306c3fb27SDimitry Andric // If this is the holding variable for a `BindingDecl`, we may already 21406c3fb27SDimitry Andric // have a storage location set up -- so check. (See also explanation below 21506c3fb27SDimitry Andric // where we process the `BindingDecl`.) 21606c3fb27SDimitry Andric if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr) 21704eeddc0SDimitry Andric return; 21804eeddc0SDimitry Andric 21906c3fb27SDimitry Andric assert(Env.getStorageLocation(D) == nullptr); 22004eeddc0SDimitry Andric 22106c3fb27SDimitry Andric Env.setStorageLocation(D, Env.createObject(D)); 22281ad6265SDimitry Andric 22306c3fb27SDimitry Andric // `DecompositionDecl` must be handled after we've interpreted the loc 22406c3fb27SDimitry Andric // itself, because the binding expression refers back to the 22506c3fb27SDimitry Andric // `DecompositionDecl` (even though it has no written name). 22681ad6265SDimitry Andric if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) { 22781ad6265SDimitry Andric // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This 22881ad6265SDimitry Andric // needs to be evaluated after initializing the values in the storage for 22981ad6265SDimitry Andric // VarDecl, as the bindings refer to them. 23081ad6265SDimitry Andric // FIXME: Add support for ArraySubscriptExpr. 231bdd1243dSDimitry Andric // FIXME: Consider adding AST nodes used in BindingDecls to the CFG. 23281ad6265SDimitry Andric for (const auto *B : Decomp->bindings()) { 233bdd1243dSDimitry Andric if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) { 23481ad6265SDimitry Andric auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase()); 23581ad6265SDimitry Andric if (DE == nullptr) 23681ad6265SDimitry Andric continue; 23781ad6265SDimitry Andric 238bdd1243dSDimitry Andric // ME and its base haven't been visited because they aren't included 239bdd1243dSDimitry Andric // in the statements of the CFG basic block. 24081ad6265SDimitry Andric VisitDeclRefExpr(DE); 24181ad6265SDimitry Andric VisitMemberExpr(ME); 24281ad6265SDimitry Andric 2435f757f3fSDimitry Andric if (auto *Loc = Env.getStorageLocation(*ME)) 24481ad6265SDimitry Andric Env.setStorageLocation(*B, *Loc); 245bdd1243dSDimitry Andric } else if (auto *VD = B->getHoldingVar()) { 24606c3fb27SDimitry Andric // Holding vars are used to back the `BindingDecl`s of tuple-like 24706c3fb27SDimitry Andric // types. The holding var declarations appear after the 24806c3fb27SDimitry Andric // `DecompositionDecl`, so we have to explicitly process them here 24906c3fb27SDimitry Andric // to know their storage location. They will be processed a second 25006c3fb27SDimitry Andric // time when we visit their `VarDecl`s, so we have code that protects 25106c3fb27SDimitry Andric // against this above. 25206c3fb27SDimitry Andric ProcessVarDecl(*VD); 25306c3fb27SDimitry Andric auto *VDLoc = Env.getStorageLocation(*VD); 25406c3fb27SDimitry Andric assert(VDLoc != nullptr); 25506c3fb27SDimitry Andric Env.setStorageLocation(*B, *VDLoc); 256bdd1243dSDimitry Andric } 25781ad6265SDimitry Andric } 25804eeddc0SDimitry Andric } 25904eeddc0SDimitry Andric } 26004eeddc0SDimitry Andric 26104eeddc0SDimitry Andric void VisitImplicitCastExpr(const ImplicitCastExpr *S) { 26281ad6265SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 26304eeddc0SDimitry Andric assert(SubExpr != nullptr); 26404eeddc0SDimitry Andric 26504eeddc0SDimitry Andric switch (S->getCastKind()) { 26681ad6265SDimitry Andric case CK_IntegralToBoolean: { 26781ad6265SDimitry Andric // This cast creates a new, boolean value from the integral value. We 26881ad6265SDimitry Andric // model that with a fresh value in the environment, unless it's already a 26981ad6265SDimitry Andric // boolean. 27006c3fb27SDimitry Andric if (auto *SubExprVal = 2715f757f3fSDimitry Andric dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr))) 2725f757f3fSDimitry Andric Env.setValue(*S, *SubExprVal); 27381ad6265SDimitry Andric else 27481ad6265SDimitry Andric // FIXME: If integer modeling is added, then update this code to create 27581ad6265SDimitry Andric // the boolean based on the integer model. 2765f757f3fSDimitry Andric Env.setValue(*S, Env.makeAtomicBoolValue()); 27781ad6265SDimitry Andric break; 27881ad6265SDimitry Andric } 27981ad6265SDimitry Andric 28004eeddc0SDimitry Andric case CK_LValueToRValue: { 281bdd1243dSDimitry Andric // When an L-value is used as an R-value, it may result in sharing, so we 2825f757f3fSDimitry Andric // need to unpack any nested `Top`s. 283bdd1243dSDimitry Andric auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env); 28404eeddc0SDimitry Andric if (SubExprVal == nullptr) 28504eeddc0SDimitry Andric break; 28604eeddc0SDimitry Andric 2875f757f3fSDimitry Andric Env.setValue(*S, *SubExprVal); 28804eeddc0SDimitry Andric break; 28904eeddc0SDimitry Andric } 29081ad6265SDimitry Andric 29181ad6265SDimitry Andric case CK_IntegralCast: 29281ad6265SDimitry Andric // FIXME: This cast creates a new integral value from the 29381ad6265SDimitry Andric // subexpression. But, because we don't model integers, we don't 29481ad6265SDimitry Andric // distinguish between this new value and the underlying one. If integer 29581ad6265SDimitry Andric // modeling is added, then update this code to create a fresh location and 29681ad6265SDimitry Andric // value. 29781ad6265SDimitry Andric case CK_UncheckedDerivedToBase: 29881ad6265SDimitry Andric case CK_ConstructorConversion: 29981ad6265SDimitry Andric case CK_UserDefinedConversion: 30081ad6265SDimitry Andric // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, 30181ad6265SDimitry Andric // CK_ConstructorConversion, and CK_UserDefinedConversion. 30204eeddc0SDimitry Andric case CK_NoOp: { 30304eeddc0SDimitry Andric // FIXME: Consider making `Environment::getStorageLocation` skip noop 30406c3fb27SDimitry Andric // expressions (this and other similar expressions in the file) instead 30506c3fb27SDimitry Andric // of assigning them storage locations. 30606c3fb27SDimitry Andric propagateValueOrStorageLocation(*SubExpr, *S, Env); 30704eeddc0SDimitry Andric break; 30804eeddc0SDimitry Andric } 30906c3fb27SDimitry Andric case CK_NullToPointer: { 31081ad6265SDimitry Andric auto &NullPointerVal = 31181ad6265SDimitry Andric Env.getOrCreateNullPointerValue(S->getType()->getPointeeType()); 3125f757f3fSDimitry Andric Env.setValue(*S, NullPointerVal); 31381ad6265SDimitry Andric break; 31481ad6265SDimitry Andric } 31506c3fb27SDimitry Andric case CK_NullToMemberPointer: 31606c3fb27SDimitry Andric // FIXME: Implement pointers to members. For now, don't associate a value 31706c3fb27SDimitry Andric // with this expression. 31806c3fb27SDimitry Andric break; 31906c3fb27SDimitry Andric case CK_FunctionToPointerDecay: { 3205f757f3fSDimitry Andric StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr); 32106c3fb27SDimitry Andric if (PointeeLoc == nullptr) 32206c3fb27SDimitry Andric break; 32306c3fb27SDimitry Andric 3245f757f3fSDimitry Andric Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc)); 32506c3fb27SDimitry Andric break; 32606c3fb27SDimitry Andric } 32706c3fb27SDimitry Andric case CK_BuiltinFnToFnPtr: 32806c3fb27SDimitry Andric // Despite its name, the result type of `BuiltinFnToFnPtr` is a function, 32906c3fb27SDimitry Andric // not a function pointer. In addition, builtin functions can only be 33006c3fb27SDimitry Andric // called directly; it is not legal to take their address. We therefore 33106c3fb27SDimitry Andric // don't need to create a value or storage location for them. 33206c3fb27SDimitry Andric break; 33304eeddc0SDimitry Andric default: 33404eeddc0SDimitry Andric break; 33504eeddc0SDimitry Andric } 33604eeddc0SDimitry Andric } 33704eeddc0SDimitry Andric 33804eeddc0SDimitry Andric void VisitUnaryOperator(const UnaryOperator *S) { 33981ad6265SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 34004eeddc0SDimitry Andric assert(SubExpr != nullptr); 34104eeddc0SDimitry Andric 34204eeddc0SDimitry Andric switch (S->getOpcode()) { 34304eeddc0SDimitry Andric case UO_Deref: { 344cb14a3feSDimitry Andric const auto *SubExprVal = Env.get<PointerValue>(*SubExpr); 34504eeddc0SDimitry Andric if (SubExprVal == nullptr) 34604eeddc0SDimitry Andric break; 34704eeddc0SDimitry Andric 3485f757f3fSDimitry Andric Env.setStorageLocation(*S, SubExprVal->getPointeeLoc()); 34904eeddc0SDimitry Andric break; 35004eeddc0SDimitry Andric } 35104eeddc0SDimitry Andric case UO_AddrOf: { 35206c3fb27SDimitry Andric // FIXME: Model pointers to members. 35306c3fb27SDimitry Andric if (S->getType()->isMemberPointerType()) 35404eeddc0SDimitry Andric break; 35504eeddc0SDimitry Andric 3565f757f3fSDimitry Andric if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr)) 3575f757f3fSDimitry Andric Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc)); 35804eeddc0SDimitry Andric break; 35904eeddc0SDimitry Andric } 36081ad6265SDimitry Andric case UO_LNot: { 3615f757f3fSDimitry Andric auto *SubExprVal = dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr)); 36281ad6265SDimitry Andric if (SubExprVal == nullptr) 36381ad6265SDimitry Andric break; 36481ad6265SDimitry Andric 3655f757f3fSDimitry Andric Env.setValue(*S, Env.makeNot(*SubExprVal)); 36681ad6265SDimitry Andric break; 36781ad6265SDimitry Andric } 36804eeddc0SDimitry Andric default: 36904eeddc0SDimitry Andric break; 37004eeddc0SDimitry Andric } 37104eeddc0SDimitry Andric } 37204eeddc0SDimitry Andric 37304eeddc0SDimitry Andric void VisitCXXThisExpr(const CXXThisExpr *S) { 37404eeddc0SDimitry Andric auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); 37581ad6265SDimitry Andric if (ThisPointeeLoc == nullptr) 37681ad6265SDimitry Andric // Unions are not supported yet, and will not have a location for the 37781ad6265SDimitry Andric // `this` expression's pointee. 37881ad6265SDimitry Andric return; 37904eeddc0SDimitry Andric 3805f757f3fSDimitry Andric Env.setValue(*S, Env.create<PointerValue>(*ThisPointeeLoc)); 38106c3fb27SDimitry Andric } 38206c3fb27SDimitry Andric 38306c3fb27SDimitry Andric void VisitCXXNewExpr(const CXXNewExpr *S) { 38406c3fb27SDimitry Andric if (Value *Val = Env.createValue(S->getType())) 3855f757f3fSDimitry Andric Env.setValue(*S, *Val); 38606c3fb27SDimitry Andric } 38706c3fb27SDimitry Andric 38806c3fb27SDimitry Andric void VisitCXXDeleteExpr(const CXXDeleteExpr *S) { 38906c3fb27SDimitry Andric // Empty method. 39006c3fb27SDimitry Andric // We consciously don't do anything on deletes. Diagnosing double deletes 39106c3fb27SDimitry Andric // (for example) should be done by a specific analysis, not by the 39206c3fb27SDimitry Andric // framework. 39304eeddc0SDimitry Andric } 39404eeddc0SDimitry Andric 395bdd1243dSDimitry Andric void VisitReturnStmt(const ReturnStmt *S) { 39606c3fb27SDimitry Andric if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts) 397bdd1243dSDimitry Andric return; 398bdd1243dSDimitry Andric 399bdd1243dSDimitry Andric auto *Ret = S->getRetValue(); 400bdd1243dSDimitry Andric if (Ret == nullptr) 401bdd1243dSDimitry Andric return; 402bdd1243dSDimitry Andric 40306c3fb27SDimitry Andric if (Ret->isPRValue()) { 4045f757f3fSDimitry Andric auto *Val = Env.getValue(*Ret); 405bdd1243dSDimitry Andric if (Val == nullptr) 406bdd1243dSDimitry Andric return; 407bdd1243dSDimitry Andric 40806c3fb27SDimitry Andric // FIXME: Model NRVO. 40906c3fb27SDimitry Andric Env.setReturnValue(Val); 41006c3fb27SDimitry Andric } else { 4115f757f3fSDimitry Andric auto *Loc = Env.getStorageLocation(*Ret); 41206c3fb27SDimitry Andric if (Loc == nullptr) 413bdd1243dSDimitry Andric return; 414bdd1243dSDimitry Andric 415bdd1243dSDimitry Andric // FIXME: Model NRVO. 41606c3fb27SDimitry Andric Env.setReturnStorageLocation(Loc); 41706c3fb27SDimitry Andric } 418bdd1243dSDimitry Andric } 419bdd1243dSDimitry Andric 42004eeddc0SDimitry Andric void VisitMemberExpr(const MemberExpr *S) { 42104eeddc0SDimitry Andric ValueDecl *Member = S->getMemberDecl(); 42204eeddc0SDimitry Andric assert(Member != nullptr); 42304eeddc0SDimitry Andric 42404eeddc0SDimitry Andric // FIXME: Consider assigning pointer values to function member expressions. 42504eeddc0SDimitry Andric if (Member->isFunctionOrFunctionTemplate()) 42604eeddc0SDimitry Andric return; 42704eeddc0SDimitry Andric 428bdd1243dSDimitry Andric // FIXME: if/when we add support for modeling enums, use that support here. 429bdd1243dSDimitry Andric if (isa<EnumConstantDecl>(Member)) 430bdd1243dSDimitry Andric return; 431bdd1243dSDimitry Andric 43281ad6265SDimitry Andric if (auto *D = dyn_cast<VarDecl>(Member)) { 43381ad6265SDimitry Andric if (D->hasGlobalStorage()) { 43406c3fb27SDimitry Andric auto *VarDeclLoc = Env.getStorageLocation(*D); 43581ad6265SDimitry Andric if (VarDeclLoc == nullptr) 43681ad6265SDimitry Andric return; 43781ad6265SDimitry Andric 43881ad6265SDimitry Andric Env.setStorageLocation(*S, *VarDeclLoc); 43981ad6265SDimitry Andric return; 44081ad6265SDimitry Andric } 44181ad6265SDimitry Andric } 44281ad6265SDimitry Andric 4435f757f3fSDimitry Andric RecordStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env); 44404eeddc0SDimitry Andric if (BaseLoc == nullptr) 44504eeddc0SDimitry Andric return; 44604eeddc0SDimitry Andric 44706c3fb27SDimitry Andric auto *MemberLoc = BaseLoc->getChild(*Member); 44806c3fb27SDimitry Andric if (MemberLoc == nullptr) 44906c3fb27SDimitry Andric return; 4505f757f3fSDimitry Andric Env.setStorageLocation(*S, *MemberLoc); 45104eeddc0SDimitry Andric } 45204eeddc0SDimitry Andric 45304eeddc0SDimitry Andric void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { 45404eeddc0SDimitry Andric const Expr *InitExpr = S->getExpr(); 45504eeddc0SDimitry Andric assert(InitExpr != nullptr); 45606c3fb27SDimitry Andric propagateValueOrStorageLocation(*InitExpr, *S, Env); 45704eeddc0SDimitry Andric } 45804eeddc0SDimitry Andric 45904eeddc0SDimitry Andric void VisitCXXConstructExpr(const CXXConstructExpr *S) { 46004eeddc0SDimitry Andric const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); 46104eeddc0SDimitry Andric assert(ConstructorDecl != nullptr); 46204eeddc0SDimitry Andric 46304eeddc0SDimitry Andric if (ConstructorDecl->isCopyOrMoveConstructor()) { 46406c3fb27SDimitry Andric // It is permissible for a copy/move constructor to have additional 46506c3fb27SDimitry Andric // parameters as long as they have default arguments defined for them. 46606c3fb27SDimitry Andric assert(S->getNumArgs() != 0); 46704eeddc0SDimitry Andric 46804eeddc0SDimitry Andric const Expr *Arg = S->getArg(0); 46904eeddc0SDimitry Andric assert(Arg != nullptr); 47004eeddc0SDimitry Andric 471cb14a3feSDimitry Andric auto *ArgLoc = Env.get<RecordStorageLocation>(*Arg); 47204eeddc0SDimitry Andric if (ArgLoc == nullptr) 47304eeddc0SDimitry Andric return; 47404eeddc0SDimitry Andric 47506c3fb27SDimitry Andric if (S->isElidable()) { 4765f757f3fSDimitry Andric if (Value *Val = Env.getValue(*ArgLoc)) 4775f757f3fSDimitry Andric Env.setValue(*S, *Val); 4785f757f3fSDimitry Andric } else { 4795f757f3fSDimitry Andric auto &Val = *cast<RecordValue>(Env.createValue(S->getType())); 4805f757f3fSDimitry Andric Env.setValue(*S, Val); 4815f757f3fSDimitry Andric copyRecord(*ArgLoc, Val.getLoc(), Env); 48204eeddc0SDimitry Andric } 48304eeddc0SDimitry Andric return; 48404eeddc0SDimitry Andric } 48504eeddc0SDimitry Andric 4865f757f3fSDimitry Andric // `CXXConstructExpr` can have array type if default-initializing an array 4875f757f3fSDimitry Andric // of records, and we currently can't create values for arrays. So check if 4885f757f3fSDimitry Andric // we've got a record type. 4895f757f3fSDimitry Andric if (S->getType()->isRecordType()) { 4905f757f3fSDimitry Andric auto &InitialVal = *cast<RecordValue>(Env.createValue(S->getType())); 4915f757f3fSDimitry Andric Env.setValue(*S, InitialVal); 4925f757f3fSDimitry Andric } 493bdd1243dSDimitry Andric 494bdd1243dSDimitry Andric transferInlineCall(S, ConstructorDecl); 49504eeddc0SDimitry Andric } 49604eeddc0SDimitry Andric 49704eeddc0SDimitry Andric void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { 49804eeddc0SDimitry Andric if (S->getOperator() == OO_Equal) { 49904eeddc0SDimitry Andric assert(S->getNumArgs() == 2); 50004eeddc0SDimitry Andric 50104eeddc0SDimitry Andric const Expr *Arg0 = S->getArg(0); 50204eeddc0SDimitry Andric assert(Arg0 != nullptr); 50304eeddc0SDimitry Andric 50404eeddc0SDimitry Andric const Expr *Arg1 = S->getArg(1); 50504eeddc0SDimitry Andric assert(Arg1 != nullptr); 50604eeddc0SDimitry Andric 50704eeddc0SDimitry Andric // Evaluate only copy and move assignment operators. 50806c3fb27SDimitry Andric const auto *Method = 50906c3fb27SDimitry Andric dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee()); 51006c3fb27SDimitry Andric if (!Method) 51106c3fb27SDimitry Andric return; 51206c3fb27SDimitry Andric if (!Method->isCopyAssignmentOperator() && 51306c3fb27SDimitry Andric !Method->isMoveAssignmentOperator()) 51404eeddc0SDimitry Andric return; 51504eeddc0SDimitry Andric 5165f757f3fSDimitry Andric RecordStorageLocation *LocSrc = nullptr; 5175f757f3fSDimitry Andric if (Arg1->isPRValue()) { 518cb14a3feSDimitry Andric if (auto *Val = Env.get<RecordValue>(*Arg1)) 5195f757f3fSDimitry Andric LocSrc = &Val->getLoc(); 5205f757f3fSDimitry Andric } else { 521cb14a3feSDimitry Andric LocSrc = Env.get<RecordStorageLocation>(*Arg1); 52206c3fb27SDimitry Andric } 523cb14a3feSDimitry Andric auto *LocDst = Env.get<RecordStorageLocation>(*Arg0); 5245f757f3fSDimitry Andric 5255f757f3fSDimitry Andric if (LocSrc == nullptr || LocDst == nullptr) 5265f757f3fSDimitry Andric return; 5275f757f3fSDimitry Andric 5285f757f3fSDimitry Andric // The assignment operators are different from the type of the destination 5295f757f3fSDimitry Andric // in this model (i.e. in one of their base classes). This must be very 5305f757f3fSDimitry Andric // rare and we just bail. 5315f757f3fSDimitry Andric if (Method->getFunctionObjectParameterType() 5325f757f3fSDimitry Andric .getCanonicalType() 5335f757f3fSDimitry Andric .getUnqualifiedType() != 5345f757f3fSDimitry Andric LocDst->getType().getCanonicalType().getUnqualifiedType()) 5355f757f3fSDimitry Andric return; 5365f757f3fSDimitry Andric 5375f757f3fSDimitry Andric copyRecord(*LocSrc, *LocDst, Env); 5385f757f3fSDimitry Andric Env.setStorageLocation(*S, *LocDst); 53904eeddc0SDimitry Andric } 54004eeddc0SDimitry Andric } 54104eeddc0SDimitry Andric 54204eeddc0SDimitry Andric void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { 54304eeddc0SDimitry Andric if (S->getCastKind() == CK_ConstructorConversion) { 54404eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 54504eeddc0SDimitry Andric assert(SubExpr != nullptr); 54604eeddc0SDimitry Andric 54706c3fb27SDimitry Andric propagateValue(*SubExpr, *S, Env); 54804eeddc0SDimitry Andric } 54904eeddc0SDimitry Andric } 55004eeddc0SDimitry Andric 55104eeddc0SDimitry Andric void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { 55204eeddc0SDimitry Andric if (Value *Val = Env.createValue(S->getType())) 5535f757f3fSDimitry Andric Env.setValue(*S, *Val); 55404eeddc0SDimitry Andric } 55504eeddc0SDimitry Andric 55604eeddc0SDimitry Andric void VisitCallExpr(const CallExpr *S) { 55781ad6265SDimitry Andric // Of clang's builtins, only `__builtin_expect` is handled explicitly, since 55881ad6265SDimitry Andric // others (like trap, debugtrap, and unreachable) are handled by CFG 55981ad6265SDimitry Andric // construction. 56004eeddc0SDimitry Andric if (S->isCallToStdMove()) { 56104eeddc0SDimitry Andric assert(S->getNumArgs() == 1); 56204eeddc0SDimitry Andric 56304eeddc0SDimitry Andric const Expr *Arg = S->getArg(0); 56404eeddc0SDimitry Andric assert(Arg != nullptr); 56504eeddc0SDimitry Andric 5665f757f3fSDimitry Andric auto *ArgLoc = Env.getStorageLocation(*Arg); 56704eeddc0SDimitry Andric if (ArgLoc == nullptr) 56804eeddc0SDimitry Andric return; 56904eeddc0SDimitry Andric 57004eeddc0SDimitry Andric Env.setStorageLocation(*S, *ArgLoc); 57181ad6265SDimitry Andric } else if (S->getDirectCallee() != nullptr && 57281ad6265SDimitry Andric S->getDirectCallee()->getBuiltinID() == 57381ad6265SDimitry Andric Builtin::BI__builtin_expect) { 57481ad6265SDimitry Andric assert(S->getNumArgs() > 0); 57581ad6265SDimitry Andric assert(S->getArg(0) != nullptr); 5765f757f3fSDimitry Andric auto *ArgVal = Env.getValue(*S->getArg(0)); 5775f757f3fSDimitry Andric if (ArgVal == nullptr) 57881ad6265SDimitry Andric return; 5795f757f3fSDimitry Andric Env.setValue(*S, *ArgVal); 580972a253aSDimitry Andric } else if (const FunctionDecl *F = S->getDirectCallee()) { 581bdd1243dSDimitry Andric transferInlineCall(S, F); 582cb14a3feSDimitry Andric 583cb14a3feSDimitry Andric // If this call produces a prvalue of record type, make sure that we have 584cb14a3feSDimitry Andric // a `RecordValue` for it. This is required so that 585cb14a3feSDimitry Andric // `Environment::getResultObjectLocation()` is able to return a location 586cb14a3feSDimitry Andric // for this `CallExpr`. 587cb14a3feSDimitry Andric if (S->getType()->isRecordType() && S->isPRValue()) 588cb14a3feSDimitry Andric if (Env.getValue(*S) == nullptr) 589cb14a3feSDimitry Andric refreshRecordValue(*S, Env); 59004eeddc0SDimitry Andric } 59104eeddc0SDimitry Andric } 59204eeddc0SDimitry Andric 59304eeddc0SDimitry Andric void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { 59404eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 59504eeddc0SDimitry Andric assert(SubExpr != nullptr); 59604eeddc0SDimitry Andric 5975f757f3fSDimitry Andric Value *SubExprVal = Env.getValue(*SubExpr); 59806c3fb27SDimitry Andric if (SubExprVal == nullptr) 59904eeddc0SDimitry Andric return; 60004eeddc0SDimitry Andric 6015f757f3fSDimitry Andric if (RecordValue *RecordVal = dyn_cast<RecordValue>(SubExprVal)) { 6025f757f3fSDimitry Andric Env.setStorageLocation(*S, RecordVal->getLoc()); 60306c3fb27SDimitry Andric return; 60406c3fb27SDimitry Andric } 60506c3fb27SDimitry Andric 60606c3fb27SDimitry Andric StorageLocation &Loc = Env.createStorageLocation(*S); 60706c3fb27SDimitry Andric Env.setValue(Loc, *SubExprVal); 60806c3fb27SDimitry Andric Env.setStorageLocation(*S, Loc); 60904eeddc0SDimitry Andric } 61004eeddc0SDimitry Andric 61104eeddc0SDimitry Andric void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { 61204eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 61304eeddc0SDimitry Andric assert(SubExpr != nullptr); 61404eeddc0SDimitry Andric 61506c3fb27SDimitry Andric propagateValue(*SubExpr, *S, Env); 61604eeddc0SDimitry Andric } 61704eeddc0SDimitry Andric 61804eeddc0SDimitry Andric void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { 61904eeddc0SDimitry Andric if (S->getCastKind() == CK_NoOp) { 62004eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 62104eeddc0SDimitry Andric assert(SubExpr != nullptr); 62204eeddc0SDimitry Andric 62306c3fb27SDimitry Andric propagateValueOrStorageLocation(*SubExpr, *S, Env); 62404eeddc0SDimitry Andric } 62504eeddc0SDimitry Andric } 62604eeddc0SDimitry Andric 62704eeddc0SDimitry Andric void VisitConditionalOperator(const ConditionalOperator *S) { 62804eeddc0SDimitry Andric // FIXME: Revisit this once flow conditions are added to the framework. For 62904eeddc0SDimitry Andric // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow 63004eeddc0SDimitry Andric // condition. 6315f757f3fSDimitry Andric // When we do this, we will need to retrieve the values of the operands from 6325f757f3fSDimitry Andric // the environments for the basic blocks they are computed in, in a similar 6335f757f3fSDimitry Andric // way to how this is done for short-circuited logical operators in 6345f757f3fSDimitry Andric // `getLogicOperatorSubExprValue()`. 63506c3fb27SDimitry Andric if (S->isGLValue()) 6365f757f3fSDimitry Andric Env.setStorageLocation(*S, Env.createObject(S->getType())); 63706c3fb27SDimitry Andric else if (Value *Val = Env.createValue(S->getType())) 6385f757f3fSDimitry Andric Env.setValue(*S, *Val); 63904eeddc0SDimitry Andric } 64004eeddc0SDimitry Andric 64104eeddc0SDimitry Andric void VisitInitListExpr(const InitListExpr *S) { 64204eeddc0SDimitry Andric QualType Type = S->getType(); 64304eeddc0SDimitry Andric 64406c3fb27SDimitry Andric if (!Type->isStructureOrClassType()) { 64506c3fb27SDimitry Andric if (auto *Val = Env.createValue(Type)) 6465f757f3fSDimitry Andric Env.setValue(*S, *Val); 64704eeddc0SDimitry Andric 64804eeddc0SDimitry Andric return; 64906c3fb27SDimitry Andric } 65004eeddc0SDimitry Andric 6515f757f3fSDimitry Andric // In case the initializer list is transparent, we just need to propagate 6525f757f3fSDimitry Andric // the value that it contains. 6535f757f3fSDimitry Andric if (S->isSemanticForm() && S->isTransparent()) { 6545f757f3fSDimitry Andric propagateValue(*S->getInit(0), *S, Env); 6555f757f3fSDimitry Andric return; 65604eeddc0SDimitry Andric } 65706c3fb27SDimitry Andric 6585f757f3fSDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 65906c3fb27SDimitry Andric 6605f757f3fSDimitry Andric // This only contains the direct fields for the given type. 6615f757f3fSDimitry Andric std::vector<FieldDecl *> FieldsForInit = 6625f757f3fSDimitry Andric getFieldsForInitListExpr(Type->getAsRecordDecl()); 66306c3fb27SDimitry Andric 6645f757f3fSDimitry Andric // `S->inits()` contains all the initializer epressions, including the 6655f757f3fSDimitry Andric // ones for direct base classes. 6665f757f3fSDimitry Andric auto Inits = S->inits(); 6675f757f3fSDimitry Andric size_t InitIdx = 0; 6685f757f3fSDimitry Andric 6695f757f3fSDimitry Andric // Initialize base classes. 6705f757f3fSDimitry Andric if (auto* R = S->getType()->getAsCXXRecordDecl()) { 6715f757f3fSDimitry Andric assert(FieldsForInit.size() + R->getNumBases() == Inits.size()); 6725f757f3fSDimitry Andric for ([[maybe_unused]] const CXXBaseSpecifier &Base : R->bases()) { 6735f757f3fSDimitry Andric assert(InitIdx < Inits.size()); 6745f757f3fSDimitry Andric auto Init = Inits[InitIdx++]; 6755f757f3fSDimitry Andric assert(Base.getType().getCanonicalType() == 6765f757f3fSDimitry Andric Init->getType().getCanonicalType()); 677cb14a3feSDimitry Andric auto *BaseVal = Env.get<RecordValue>(*Init); 6785f757f3fSDimitry Andric if (!BaseVal) 6795f757f3fSDimitry Andric BaseVal = cast<RecordValue>(Env.createValue(Init->getType())); 6805f757f3fSDimitry Andric // Take ownership of the fields of the `RecordValue` for the base class 6815f757f3fSDimitry Andric // and incorporate them into the "flattened" set of fields for the 6825f757f3fSDimitry Andric // derived class. 6835f757f3fSDimitry Andric auto Children = BaseVal->getLoc().children(); 6845f757f3fSDimitry Andric FieldLocs.insert(Children.begin(), Children.end()); 6855f757f3fSDimitry Andric } 6865f757f3fSDimitry Andric } 6875f757f3fSDimitry Andric 6885f757f3fSDimitry Andric assert(FieldsForInit.size() == Inits.size() - InitIdx); 6895f757f3fSDimitry Andric for (auto Field : FieldsForInit) { 6905f757f3fSDimitry Andric assert(InitIdx < Inits.size()); 6915f757f3fSDimitry Andric auto Init = Inits[InitIdx++]; 6925f757f3fSDimitry Andric assert( 6935f757f3fSDimitry Andric // The types are same, or 6945f757f3fSDimitry Andric Field->getType().getCanonicalType().getUnqualifiedType() == 6955f757f3fSDimitry Andric Init->getType().getCanonicalType().getUnqualifiedType() || 6965f757f3fSDimitry Andric // The field's type is T&, and initializer is T 6975f757f3fSDimitry Andric (Field->getType()->isReferenceType() && 6985f757f3fSDimitry Andric Field->getType().getCanonicalType()->getPointeeType() == 6995f757f3fSDimitry Andric Init->getType().getCanonicalType())); 7005f757f3fSDimitry Andric auto& Loc = Env.createObject(Field->getType(), Init); 7015f757f3fSDimitry Andric FieldLocs.insert({Field, &Loc}); 7025f757f3fSDimitry Andric } 7035f757f3fSDimitry Andric 7045f757f3fSDimitry Andric // Check that we satisfy the invariant that a `RecordStorageLoation` 7055f757f3fSDimitry Andric // contains exactly the set of modeled fields for that type. 7065f757f3fSDimitry Andric // `ModeledFields` includes fields from all the bases, but only the 7075f757f3fSDimitry Andric // modeled ones. However, if a class type is initialized with an 7085f757f3fSDimitry Andric // `InitListExpr`, all fields in the class, including those from base 7095f757f3fSDimitry Andric // classes, are included in the set of modeled fields. The code above 7105f757f3fSDimitry Andric // should therefore populate exactly the modeled fields. 7115f757f3fSDimitry Andric assert(containsSameFields( 7125f757f3fSDimitry Andric Env.getDataflowAnalysisContext().getModeledFields(Type), FieldLocs)); 7135f757f3fSDimitry Andric 7145f757f3fSDimitry Andric RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs; 7155f757f3fSDimitry Andric for (const auto &Entry : 7165f757f3fSDimitry Andric Env.getDataflowAnalysisContext().getSyntheticFields(Type)) { 7175f757f3fSDimitry Andric SyntheticFieldLocs.insert( 7185f757f3fSDimitry Andric {Entry.getKey(), &Env.createObject(Entry.getValue())}); 7195f757f3fSDimitry Andric } 7205f757f3fSDimitry Andric 7215f757f3fSDimitry Andric auto &Loc = Env.getDataflowAnalysisContext().createRecordStorageLocation( 7225f757f3fSDimitry Andric Type, std::move(FieldLocs), std::move(SyntheticFieldLocs)); 7235f757f3fSDimitry Andric RecordValue &RecordVal = Env.create<RecordValue>(Loc); 7245f757f3fSDimitry Andric 7255f757f3fSDimitry Andric Env.setValue(Loc, RecordVal); 7265f757f3fSDimitry Andric 7275f757f3fSDimitry Andric Env.setValue(*S, RecordVal); 72806c3fb27SDimitry Andric 72904eeddc0SDimitry Andric // FIXME: Implement array initialization. 73004eeddc0SDimitry Andric } 73104eeddc0SDimitry Andric 73204eeddc0SDimitry Andric void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { 7335f757f3fSDimitry Andric Env.setValue(*S, Env.getBoolLiteralValue(S->getValue())); 73406c3fb27SDimitry Andric } 73506c3fb27SDimitry Andric 73606c3fb27SDimitry Andric void VisitIntegerLiteral(const IntegerLiteral *S) { 7375f757f3fSDimitry Andric Env.setValue(*S, Env.getIntLiteralValue(S->getValue())); 73804eeddc0SDimitry Andric } 73904eeddc0SDimitry Andric 74081ad6265SDimitry Andric void VisitParenExpr(const ParenExpr *S) { 74181ad6265SDimitry Andric // The CFG does not contain `ParenExpr` as top-level statements in basic 74281ad6265SDimitry Andric // blocks, however manual traversal to sub-expressions may encounter them. 74381ad6265SDimitry Andric // Redirect to the sub-expression. 74481ad6265SDimitry Andric auto *SubExpr = S->getSubExpr(); 74581ad6265SDimitry Andric assert(SubExpr != nullptr); 74681ad6265SDimitry Andric Visit(SubExpr); 74781ad6265SDimitry Andric } 74881ad6265SDimitry Andric 74981ad6265SDimitry Andric void VisitExprWithCleanups(const ExprWithCleanups *S) { 75081ad6265SDimitry Andric // The CFG does not contain `ExprWithCleanups` as top-level statements in 75181ad6265SDimitry Andric // basic blocks, however manual traversal to sub-expressions may encounter 75281ad6265SDimitry Andric // them. Redirect to the sub-expression. 75381ad6265SDimitry Andric auto *SubExpr = S->getSubExpr(); 75481ad6265SDimitry Andric assert(SubExpr != nullptr); 75581ad6265SDimitry Andric Visit(SubExpr); 75681ad6265SDimitry Andric } 75781ad6265SDimitry Andric 75804eeddc0SDimitry Andric private: 75906c3fb27SDimitry Andric /// Returns the value for the sub-expression `SubExpr` of a logic operator. 76081ad6265SDimitry Andric BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { 76181ad6265SDimitry Andric // `SubExpr` and its parent logic operator might be part of different basic 76281ad6265SDimitry Andric // blocks. We try to access the value that is assigned to `SubExpr` in the 76381ad6265SDimitry Andric // corresponding environment. 76406c3fb27SDimitry Andric if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) 76506c3fb27SDimitry Andric if (auto *Val = 7665f757f3fSDimitry Andric dyn_cast_or_null<BoolValue>(SubExprEnv->getValue(SubExpr))) 76781ad6265SDimitry Andric return *Val; 76881ad6265SDimitry Andric 76906c3fb27SDimitry Andric // The sub-expression may lie within a basic block that isn't reachable, 77006c3fb27SDimitry Andric // even if we need it to evaluate the current (reachable) expression 77106c3fb27SDimitry Andric // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr` 77206c3fb27SDimitry Andric // within the current environment and then try to get the value that gets 77306c3fb27SDimitry Andric // assigned to it. 7745f757f3fSDimitry Andric if (Env.getValue(SubExpr) == nullptr) 77581ad6265SDimitry Andric Visit(&SubExpr); 7765f757f3fSDimitry Andric if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValue(SubExpr))) 77781ad6265SDimitry Andric return *Val; 77881ad6265SDimitry Andric 77981ad6265SDimitry Andric // If the value of `SubExpr` is still unknown, we create a fresh symbolic 78081ad6265SDimitry Andric // boolean value for it. 78181ad6265SDimitry Andric return Env.makeAtomicBoolValue(); 78281ad6265SDimitry Andric } 78381ad6265SDimitry Andric 784bdd1243dSDimitry Andric // If context sensitivity is enabled, try to analyze the body of the callee 785bdd1243dSDimitry Andric // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`. 786bdd1243dSDimitry Andric template <typename E> 787bdd1243dSDimitry Andric void transferInlineCall(const E *S, const FunctionDecl *F) { 78806c3fb27SDimitry Andric const auto &Options = Env.getDataflowAnalysisContext().getOptions(); 789bdd1243dSDimitry Andric if (!(Options.ContextSensitiveOpts && 790bdd1243dSDimitry Andric Env.canDescend(Options.ContextSensitiveOpts->Depth, F))) 791bdd1243dSDimitry Andric return; 792bdd1243dSDimitry Andric 79306c3fb27SDimitry Andric const ControlFlowContext *CFCtx = 79406c3fb27SDimitry Andric Env.getDataflowAnalysisContext().getControlFlowContext(F); 795bdd1243dSDimitry Andric if (!CFCtx) 796bdd1243dSDimitry Andric return; 797bdd1243dSDimitry Andric 798bdd1243dSDimitry Andric // FIXME: We don't support context-sensitive analysis of recursion, so 799bdd1243dSDimitry Andric // we should return early here if `F` is the same as the `FunctionDecl` 800bdd1243dSDimitry Andric // holding `S` itself. 801bdd1243dSDimitry Andric 802bdd1243dSDimitry Andric auto ExitBlock = CFCtx->getCFG().getExit().getBlockID(); 803bdd1243dSDimitry Andric 804bdd1243dSDimitry Andric auto CalleeEnv = Env.pushCall(S); 805bdd1243dSDimitry Andric 806bdd1243dSDimitry Andric // FIXME: Use the same analysis as the caller for the callee. Note, 807bdd1243dSDimitry Andric // though, that doing so would require support for changing the analysis's 808bdd1243dSDimitry Andric // ASTContext. 8095f757f3fSDimitry Andric auto Analysis = NoopAnalysis(CFCtx->getDecl().getASTContext(), 810bdd1243dSDimitry Andric DataflowAnalysisOptions{Options}); 811bdd1243dSDimitry Andric 812bdd1243dSDimitry Andric auto BlockToOutputState = 813bdd1243dSDimitry Andric dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv); 814bdd1243dSDimitry Andric assert(BlockToOutputState); 815bdd1243dSDimitry Andric assert(ExitBlock < BlockToOutputState->size()); 816bdd1243dSDimitry Andric 81706c3fb27SDimitry Andric auto &ExitState = (*BlockToOutputState)[ExitBlock]; 818bdd1243dSDimitry Andric assert(ExitState); 819bdd1243dSDimitry Andric 82006c3fb27SDimitry Andric Env.popCall(S, ExitState->Env); 821bdd1243dSDimitry Andric } 822bdd1243dSDimitry Andric 82381ad6265SDimitry Andric const StmtToEnvMap &StmtToEnv; 82404eeddc0SDimitry Andric Environment &Env; 82504eeddc0SDimitry Andric }; 82604eeddc0SDimitry Andric 82706c3fb27SDimitry Andric } // namespace 82806c3fb27SDimitry Andric 829bdd1243dSDimitry Andric void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { 830bdd1243dSDimitry Andric TransferVisitor(StmtToEnv, Env).Visit(&S); 83104eeddc0SDimitry Andric } 83204eeddc0SDimitry Andric 83304eeddc0SDimitry Andric } // namespace dataflow 83404eeddc0SDimitry Andric } // namespace clang 835