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