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" 2681ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 2781ad6265SDimitry Andric #include "clang/Basic/Builtins.h" 2804eeddc0SDimitry Andric #include "clang/Basic/OperatorKinds.h" 2904eeddc0SDimitry Andric #include "llvm/ADT/STLExtras.h" 3004eeddc0SDimitry Andric #include "llvm/Support/Casting.h" 31*bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h" 3204eeddc0SDimitry Andric #include <cassert> 3304eeddc0SDimitry Andric #include <memory> 3404eeddc0SDimitry Andric #include <tuple> 3504eeddc0SDimitry Andric 3604eeddc0SDimitry Andric namespace clang { 3704eeddc0SDimitry Andric namespace dataflow { 3804eeddc0SDimitry Andric 3981ad6265SDimitry Andric static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, 4081ad6265SDimitry Andric Environment &Env) { 4181ad6265SDimitry Andric if (auto *LHSValue = 4281ad6265SDimitry Andric dyn_cast_or_null<BoolValue>(Env.getValue(LHS, SkipPast::Reference))) 4381ad6265SDimitry Andric if (auto *RHSValue = 4481ad6265SDimitry Andric dyn_cast_or_null<BoolValue>(Env.getValue(RHS, SkipPast::Reference))) 4581ad6265SDimitry Andric return Env.makeIff(*LHSValue, *RHSValue); 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric return Env.makeAtomicBoolValue(); 4804eeddc0SDimitry Andric } 4904eeddc0SDimitry Andric 50*bdd1243dSDimitry Andric // Functionally updates `V` such that any instances of `TopBool` are replaced 51*bdd1243dSDimitry Andric // with fresh atomic bools. Note: This implementation assumes that `B` is a 52*bdd1243dSDimitry Andric // tree; if `B` is a DAG, it will lose any sharing between subvalues that was 53*bdd1243dSDimitry Andric // present in the original . 54*bdd1243dSDimitry Andric static BoolValue &unpackValue(BoolValue &V, Environment &Env); 55*bdd1243dSDimitry Andric 56*bdd1243dSDimitry Andric template <typename Derived, typename M> 57*bdd1243dSDimitry Andric BoolValue &unpackBinaryBoolValue(Environment &Env, BoolValue &B, M build) { 58*bdd1243dSDimitry Andric auto &V = *cast<Derived>(&B); 59*bdd1243dSDimitry Andric BoolValue &Left = V.getLeftSubValue(); 60*bdd1243dSDimitry Andric BoolValue &Right = V.getRightSubValue(); 61*bdd1243dSDimitry Andric BoolValue &ULeft = unpackValue(Left, Env); 62*bdd1243dSDimitry Andric BoolValue &URight = unpackValue(Right, Env); 63*bdd1243dSDimitry Andric 64*bdd1243dSDimitry Andric if (&ULeft == &Left && &URight == &Right) 65*bdd1243dSDimitry Andric return V; 66*bdd1243dSDimitry Andric 67*bdd1243dSDimitry Andric return (Env.*build)(ULeft, URight); 68*bdd1243dSDimitry Andric } 69*bdd1243dSDimitry Andric 70*bdd1243dSDimitry Andric static BoolValue &unpackValue(BoolValue &V, Environment &Env) { 71*bdd1243dSDimitry Andric switch (V.getKind()) { 72*bdd1243dSDimitry Andric case Value::Kind::Integer: 73*bdd1243dSDimitry Andric case Value::Kind::Reference: 74*bdd1243dSDimitry Andric case Value::Kind::Pointer: 75*bdd1243dSDimitry Andric case Value::Kind::Struct: 76*bdd1243dSDimitry Andric llvm_unreachable("BoolValue cannot have any of these kinds."); 77*bdd1243dSDimitry Andric 78*bdd1243dSDimitry Andric case Value::Kind::AtomicBool: 79*bdd1243dSDimitry Andric return V; 80*bdd1243dSDimitry Andric 81*bdd1243dSDimitry Andric case Value::Kind::TopBool: 82*bdd1243dSDimitry Andric // Unpack `TopBool` into a fresh atomic bool. 83*bdd1243dSDimitry Andric return Env.makeAtomicBoolValue(); 84*bdd1243dSDimitry Andric 85*bdd1243dSDimitry Andric case Value::Kind::Negation: { 86*bdd1243dSDimitry Andric auto &N = *cast<NegationValue>(&V); 87*bdd1243dSDimitry Andric BoolValue &Sub = N.getSubVal(); 88*bdd1243dSDimitry Andric BoolValue &USub = unpackValue(Sub, Env); 89*bdd1243dSDimitry Andric 90*bdd1243dSDimitry Andric if (&USub == &Sub) 91*bdd1243dSDimitry Andric return V; 92*bdd1243dSDimitry Andric return Env.makeNot(USub); 93*bdd1243dSDimitry Andric } 94*bdd1243dSDimitry Andric case Value::Kind::Conjunction: 95*bdd1243dSDimitry Andric return unpackBinaryBoolValue<ConjunctionValue>(Env, V, 96*bdd1243dSDimitry Andric &Environment::makeAnd); 97*bdd1243dSDimitry Andric case Value::Kind::Disjunction: 98*bdd1243dSDimitry Andric return unpackBinaryBoolValue<DisjunctionValue>(Env, V, 99*bdd1243dSDimitry Andric &Environment::makeOr); 100*bdd1243dSDimitry Andric case Value::Kind::Implication: 101*bdd1243dSDimitry Andric return unpackBinaryBoolValue<ImplicationValue>( 102*bdd1243dSDimitry Andric Env, V, &Environment::makeImplication); 103*bdd1243dSDimitry Andric case Value::Kind::Biconditional: 104*bdd1243dSDimitry Andric return unpackBinaryBoolValue<BiconditionalValue>(Env, V, 105*bdd1243dSDimitry Andric &Environment::makeIff); 106*bdd1243dSDimitry Andric } 107*bdd1243dSDimitry Andric llvm_unreachable("All reachable cases in switch return"); 108*bdd1243dSDimitry Andric } 109*bdd1243dSDimitry Andric 110*bdd1243dSDimitry Andric // Unpacks the value (if any) associated with `E` and updates `E` to the new 111*bdd1243dSDimitry Andric // value, if any unpacking occured. 112*bdd1243dSDimitry Andric static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) { 113*bdd1243dSDimitry Andric // FIXME: this is too flexible: it _allows_ a reference, while it should 114*bdd1243dSDimitry Andric // _require_ one, since lvalues should always be wrapped in `ReferenceValue`. 115*bdd1243dSDimitry Andric auto *Loc = Env.getStorageLocation(E, SkipPast::Reference); 116*bdd1243dSDimitry Andric if (Loc == nullptr) 117*bdd1243dSDimitry Andric return nullptr; 118*bdd1243dSDimitry Andric auto *Val = Env.getValue(*Loc); 119*bdd1243dSDimitry Andric 120*bdd1243dSDimitry Andric auto *B = dyn_cast_or_null<BoolValue>(Val); 121*bdd1243dSDimitry Andric if (B == nullptr) 122*bdd1243dSDimitry Andric return Val; 123*bdd1243dSDimitry Andric 124*bdd1243dSDimitry Andric auto &UnpackedVal = unpackValue(*B, Env); 125*bdd1243dSDimitry Andric if (&UnpackedVal == Val) 126*bdd1243dSDimitry Andric return Val; 127*bdd1243dSDimitry Andric Env.setValue(*Loc, UnpackedVal); 128*bdd1243dSDimitry Andric return &UnpackedVal; 129*bdd1243dSDimitry Andric } 130*bdd1243dSDimitry Andric 13104eeddc0SDimitry Andric class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { 13204eeddc0SDimitry Andric public: 133*bdd1243dSDimitry Andric TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env) 134*bdd1243dSDimitry Andric : StmtToEnv(StmtToEnv), Env(Env) {} 13504eeddc0SDimitry Andric 13604eeddc0SDimitry Andric void VisitBinaryOperator(const BinaryOperator *S) { 13781ad6265SDimitry Andric const Expr *LHS = S->getLHS(); 13804eeddc0SDimitry Andric assert(LHS != nullptr); 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric const Expr *RHS = S->getRHS(); 14181ad6265SDimitry Andric assert(RHS != nullptr); 14281ad6265SDimitry Andric 14381ad6265SDimitry Andric switch (S->getOpcode()) { 14481ad6265SDimitry Andric case BO_Assign: { 14504eeddc0SDimitry Andric auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference); 14604eeddc0SDimitry Andric if (LHSLoc == nullptr) 14781ad6265SDimitry Andric break; 14804eeddc0SDimitry Andric 14981ad6265SDimitry Andric auto *RHSVal = Env.getValue(*RHS, SkipPast::Reference); 15004eeddc0SDimitry Andric if (RHSVal == nullptr) 15181ad6265SDimitry Andric break; 15204eeddc0SDimitry Andric 15304eeddc0SDimitry Andric // Assign a value to the storage location of the left-hand side. 15404eeddc0SDimitry Andric Env.setValue(*LHSLoc, *RHSVal); 15504eeddc0SDimitry Andric 15604eeddc0SDimitry Andric // Assign a storage location for the whole expression. 15704eeddc0SDimitry Andric Env.setStorageLocation(*S, *LHSLoc); 15881ad6265SDimitry Andric break; 15904eeddc0SDimitry Andric } 16081ad6265SDimitry Andric case BO_LAnd: 16181ad6265SDimitry Andric case BO_LOr: { 16281ad6265SDimitry Andric BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS); 16381ad6265SDimitry Andric BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS); 16481ad6265SDimitry Andric 16581ad6265SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 16681ad6265SDimitry Andric Env.setStorageLocation(*S, Loc); 16781ad6265SDimitry Andric if (S->getOpcode() == BO_LAnd) 16881ad6265SDimitry Andric Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal)); 16981ad6265SDimitry Andric else 17081ad6265SDimitry Andric Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal)); 17181ad6265SDimitry Andric break; 17281ad6265SDimitry Andric } 17381ad6265SDimitry Andric case BO_NE: 17481ad6265SDimitry Andric case BO_EQ: { 17581ad6265SDimitry Andric auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env); 17681ad6265SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 17781ad6265SDimitry Andric Env.setStorageLocation(*S, Loc); 17881ad6265SDimitry Andric Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue 17981ad6265SDimitry Andric : Env.makeNot(LHSEqRHSValue)); 18081ad6265SDimitry Andric break; 18181ad6265SDimitry Andric } 18281ad6265SDimitry Andric case BO_Comma: { 18381ad6265SDimitry Andric if (auto *Loc = Env.getStorageLocation(*RHS, SkipPast::None)) 18481ad6265SDimitry Andric Env.setStorageLocation(*S, *Loc); 18581ad6265SDimitry Andric break; 18681ad6265SDimitry Andric } 18781ad6265SDimitry Andric default: 18881ad6265SDimitry Andric break; 18981ad6265SDimitry Andric } 19004eeddc0SDimitry Andric } 19104eeddc0SDimitry Andric 19204eeddc0SDimitry Andric void VisitDeclRefExpr(const DeclRefExpr *S) { 193*bdd1243dSDimitry Andric const ValueDecl *VD = S->getDecl(); 194*bdd1243dSDimitry Andric assert(VD != nullptr); 195*bdd1243dSDimitry Andric auto *DeclLoc = Env.getStorageLocation(*VD, SkipPast::None); 19604eeddc0SDimitry Andric if (DeclLoc == nullptr) 19704eeddc0SDimitry Andric return; 19804eeddc0SDimitry Andric 199*bdd1243dSDimitry Andric if (VD->getType()->isReferenceType()) { 200*bdd1243dSDimitry Andric assert(isa_and_nonnull<ReferenceValue>(Env.getValue((*DeclLoc))) && 201*bdd1243dSDimitry Andric "reference-typed declarations map to `ReferenceValue`s"); 20204eeddc0SDimitry Andric Env.setStorageLocation(*S, *DeclLoc); 20304eeddc0SDimitry Andric } else { 20404eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 20504eeddc0SDimitry Andric auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc)); 20604eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 20704eeddc0SDimitry Andric Env.setValue(Loc, Val); 20804eeddc0SDimitry Andric } 20904eeddc0SDimitry Andric } 21004eeddc0SDimitry Andric 21104eeddc0SDimitry Andric void VisitDeclStmt(const DeclStmt *S) { 21204eeddc0SDimitry Andric // Group decls are converted into single decls in the CFG so the cast below 21304eeddc0SDimitry Andric // is safe. 21404eeddc0SDimitry Andric const auto &D = *cast<VarDecl>(S->getSingleDecl()); 21581ad6265SDimitry Andric 21681ad6265SDimitry Andric // Static local vars are already initialized in `Environment`. 21781ad6265SDimitry Andric if (D.hasGlobalStorage()) 21881ad6265SDimitry Andric return; 21981ad6265SDimitry Andric 220*bdd1243dSDimitry Andric // The storage location for `D` could have been created earlier, before the 221*bdd1243dSDimitry Andric // variable's declaration statement (for example, in the case of 222*bdd1243dSDimitry Andric // BindingDecls). 223*bdd1243dSDimitry Andric auto *MaybeLoc = Env.getStorageLocation(D, SkipPast::None); 224*bdd1243dSDimitry Andric if (MaybeLoc == nullptr) { 225*bdd1243dSDimitry Andric MaybeLoc = &Env.createStorageLocation(D); 226*bdd1243dSDimitry Andric Env.setStorageLocation(D, *MaybeLoc); 227*bdd1243dSDimitry Andric } 228*bdd1243dSDimitry Andric auto &Loc = *MaybeLoc; 22904eeddc0SDimitry Andric 23004eeddc0SDimitry Andric const Expr *InitExpr = D.getInit(); 23104eeddc0SDimitry Andric if (InitExpr == nullptr) { 23204eeddc0SDimitry Andric // No initializer expression - associate `Loc` with a new value. 23304eeddc0SDimitry Andric if (Value *Val = Env.createValue(D.getType())) 23404eeddc0SDimitry Andric Env.setValue(Loc, *Val); 23504eeddc0SDimitry Andric return; 23604eeddc0SDimitry Andric } 23704eeddc0SDimitry Andric 23804eeddc0SDimitry Andric if (D.getType()->isReferenceType()) { 23904eeddc0SDimitry Andric // Initializing a reference variable - do not create a reference to 24004eeddc0SDimitry Andric // reference. 24104eeddc0SDimitry Andric if (auto *InitExprLoc = 24204eeddc0SDimitry Andric Env.getStorageLocation(*InitExpr, SkipPast::Reference)) { 24304eeddc0SDimitry Andric auto &Val = 24404eeddc0SDimitry Andric Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc)); 24504eeddc0SDimitry Andric Env.setValue(Loc, Val); 24604eeddc0SDimitry Andric } 24781ad6265SDimitry Andric } else if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) { 24881ad6265SDimitry Andric Env.setValue(Loc, *InitExprVal); 24904eeddc0SDimitry Andric } 25004eeddc0SDimitry Andric 25181ad6265SDimitry Andric if (Env.getValue(Loc) == nullptr) { 25281ad6265SDimitry Andric // We arrive here in (the few) cases where an expression is intentionally 25381ad6265SDimitry Andric // "uninterpreted". There are two ways to handle this situation: propagate 25481ad6265SDimitry Andric // the status, so that uninterpreted initializers result in uninterpreted 25581ad6265SDimitry Andric // variables, or provide a default value. We choose the latter so that 25681ad6265SDimitry Andric // later refinements of the variable can be used for reasoning about the 25781ad6265SDimitry Andric // surrounding code. 25881ad6265SDimitry Andric // 25981ad6265SDimitry Andric // FIXME. If and when we interpret all language cases, change this to 26081ad6265SDimitry Andric // assert that `InitExpr` is interpreted, rather than supplying a default 26181ad6265SDimitry Andric // value (assuming we don't update the environment API to return 26281ad6265SDimitry Andric // references). 26304eeddc0SDimitry Andric if (Value *Val = Env.createValue(D.getType())) 26404eeddc0SDimitry Andric Env.setValue(Loc, *Val); 26581ad6265SDimitry Andric } 26681ad6265SDimitry Andric 26781ad6265SDimitry Andric if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) { 26881ad6265SDimitry Andric // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This 26981ad6265SDimitry Andric // needs to be evaluated after initializing the values in the storage for 27081ad6265SDimitry Andric // VarDecl, as the bindings refer to them. 27181ad6265SDimitry Andric // FIXME: Add support for ArraySubscriptExpr. 272*bdd1243dSDimitry Andric // FIXME: Consider adding AST nodes used in BindingDecls to the CFG. 27381ad6265SDimitry Andric for (const auto *B : Decomp->bindings()) { 274*bdd1243dSDimitry Andric if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) { 27581ad6265SDimitry Andric auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase()); 27681ad6265SDimitry Andric if (DE == nullptr) 27781ad6265SDimitry Andric continue; 27881ad6265SDimitry Andric 279*bdd1243dSDimitry Andric // ME and its base haven't been visited because they aren't included 280*bdd1243dSDimitry Andric // in the statements of the CFG basic block. 28181ad6265SDimitry Andric VisitDeclRefExpr(DE); 28281ad6265SDimitry Andric VisitMemberExpr(ME); 28381ad6265SDimitry Andric 28481ad6265SDimitry Andric if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference)) 28581ad6265SDimitry Andric Env.setStorageLocation(*B, *Loc); 286*bdd1243dSDimitry Andric } else if (auto *VD = B->getHoldingVar()) { 287*bdd1243dSDimitry Andric // Holding vars are used to back the BindingDecls of tuple-like 288*bdd1243dSDimitry Andric // types. The holding var declarations appear *after* this statement, 289*bdd1243dSDimitry Andric // so we have to create a location for them here to share with `B`. We 290*bdd1243dSDimitry Andric // don't visit the binding, because we know it will be a DeclRefExpr 291*bdd1243dSDimitry Andric // to `VD`. 292*bdd1243dSDimitry Andric auto &VDLoc = Env.createStorageLocation(*VD); 293*bdd1243dSDimitry Andric Env.setStorageLocation(*VD, VDLoc); 294*bdd1243dSDimitry Andric Env.setStorageLocation(*B, VDLoc); 295*bdd1243dSDimitry Andric } 29681ad6265SDimitry Andric } 29704eeddc0SDimitry Andric } 29804eeddc0SDimitry Andric } 29904eeddc0SDimitry Andric 30004eeddc0SDimitry Andric void VisitImplicitCastExpr(const ImplicitCastExpr *S) { 30181ad6265SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 30204eeddc0SDimitry Andric assert(SubExpr != nullptr); 30304eeddc0SDimitry Andric 30404eeddc0SDimitry Andric switch (S->getCastKind()) { 30581ad6265SDimitry Andric case CK_IntegralToBoolean: { 30681ad6265SDimitry Andric // This cast creates a new, boolean value from the integral value. We 30781ad6265SDimitry Andric // model that with a fresh value in the environment, unless it's already a 30881ad6265SDimitry Andric // boolean. 30981ad6265SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 31081ad6265SDimitry Andric Env.setStorageLocation(*S, Loc); 31181ad6265SDimitry Andric if (auto *SubExprVal = dyn_cast_or_null<BoolValue>( 31281ad6265SDimitry Andric Env.getValue(*SubExpr, SkipPast::Reference))) 31381ad6265SDimitry Andric Env.setValue(Loc, *SubExprVal); 31481ad6265SDimitry Andric else 31581ad6265SDimitry Andric // FIXME: If integer modeling is added, then update this code to create 31681ad6265SDimitry Andric // the boolean based on the integer model. 31781ad6265SDimitry Andric Env.setValue(Loc, Env.makeAtomicBoolValue()); 31881ad6265SDimitry Andric break; 31981ad6265SDimitry Andric } 32081ad6265SDimitry Andric 32104eeddc0SDimitry Andric case CK_LValueToRValue: { 322*bdd1243dSDimitry Andric // When an L-value is used as an R-value, it may result in sharing, so we 323*bdd1243dSDimitry Andric // need to unpack any nested `Top`s. 324*bdd1243dSDimitry Andric auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env); 32504eeddc0SDimitry Andric if (SubExprVal == nullptr) 32604eeddc0SDimitry Andric break; 32704eeddc0SDimitry Andric 32804eeddc0SDimitry Andric auto &ExprLoc = Env.createStorageLocation(*S); 32904eeddc0SDimitry Andric Env.setStorageLocation(*S, ExprLoc); 33004eeddc0SDimitry Andric Env.setValue(ExprLoc, *SubExprVal); 33104eeddc0SDimitry Andric break; 33204eeddc0SDimitry Andric } 33381ad6265SDimitry Andric 33481ad6265SDimitry Andric case CK_IntegralCast: 33581ad6265SDimitry Andric // FIXME: This cast creates a new integral value from the 33681ad6265SDimitry Andric // subexpression. But, because we don't model integers, we don't 33781ad6265SDimitry Andric // distinguish between this new value and the underlying one. If integer 33881ad6265SDimitry Andric // modeling is added, then update this code to create a fresh location and 33981ad6265SDimitry Andric // value. 34081ad6265SDimitry Andric case CK_UncheckedDerivedToBase: 34181ad6265SDimitry Andric case CK_ConstructorConversion: 34281ad6265SDimitry Andric case CK_UserDefinedConversion: 34381ad6265SDimitry Andric // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, 34481ad6265SDimitry Andric // CK_ConstructorConversion, and CK_UserDefinedConversion. 34504eeddc0SDimitry Andric case CK_NoOp: { 34604eeddc0SDimitry Andric // FIXME: Consider making `Environment::getStorageLocation` skip noop 34704eeddc0SDimitry Andric // expressions (this and other similar expressions in the file) instead of 34804eeddc0SDimitry Andric // assigning them storage locations. 34904eeddc0SDimitry Andric auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 35004eeddc0SDimitry Andric if (SubExprLoc == nullptr) 35104eeddc0SDimitry Andric break; 35204eeddc0SDimitry Andric 35304eeddc0SDimitry Andric Env.setStorageLocation(*S, *SubExprLoc); 35404eeddc0SDimitry Andric break; 35504eeddc0SDimitry Andric } 35681ad6265SDimitry Andric case CK_NullToPointer: 35781ad6265SDimitry Andric case CK_NullToMemberPointer: { 35881ad6265SDimitry Andric auto &Loc = Env.createStorageLocation(S->getType()); 35981ad6265SDimitry Andric Env.setStorageLocation(*S, Loc); 36081ad6265SDimitry Andric 36181ad6265SDimitry Andric auto &NullPointerVal = 36281ad6265SDimitry Andric Env.getOrCreateNullPointerValue(S->getType()->getPointeeType()); 36381ad6265SDimitry Andric Env.setValue(Loc, NullPointerVal); 36481ad6265SDimitry Andric break; 36581ad6265SDimitry Andric } 36604eeddc0SDimitry Andric default: 36704eeddc0SDimitry Andric break; 36804eeddc0SDimitry Andric } 36904eeddc0SDimitry Andric } 37004eeddc0SDimitry Andric 37104eeddc0SDimitry Andric void VisitUnaryOperator(const UnaryOperator *S) { 37281ad6265SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 37304eeddc0SDimitry Andric assert(SubExpr != nullptr); 37404eeddc0SDimitry Andric 37504eeddc0SDimitry Andric switch (S->getOpcode()) { 37604eeddc0SDimitry Andric case UO_Deref: { 37704eeddc0SDimitry Andric // Skip past a reference to handle dereference of a dependent pointer. 37804eeddc0SDimitry Andric const auto *SubExprVal = cast_or_null<PointerValue>( 37904eeddc0SDimitry Andric Env.getValue(*SubExpr, SkipPast::Reference)); 38004eeddc0SDimitry Andric if (SubExprVal == nullptr) 38104eeddc0SDimitry Andric break; 38204eeddc0SDimitry Andric 38304eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 38404eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 38504eeddc0SDimitry Andric Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>( 38604eeddc0SDimitry Andric SubExprVal->getPointeeLoc()))); 38704eeddc0SDimitry Andric break; 38804eeddc0SDimitry Andric } 38904eeddc0SDimitry Andric case UO_AddrOf: { 39004eeddc0SDimitry Andric // Do not form a pointer to a reference. If `SubExpr` is assigned a 39104eeddc0SDimitry Andric // `ReferenceValue` then form a value that points to the location of its 39204eeddc0SDimitry Andric // pointee. 39304eeddc0SDimitry Andric StorageLocation *PointeeLoc = 39404eeddc0SDimitry Andric Env.getStorageLocation(*SubExpr, SkipPast::Reference); 39504eeddc0SDimitry Andric if (PointeeLoc == nullptr) 39604eeddc0SDimitry Andric break; 39704eeddc0SDimitry Andric 39804eeddc0SDimitry Andric auto &PointerLoc = Env.createStorageLocation(*S); 39904eeddc0SDimitry Andric auto &PointerVal = 40004eeddc0SDimitry Andric Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc)); 40104eeddc0SDimitry Andric Env.setStorageLocation(*S, PointerLoc); 40204eeddc0SDimitry Andric Env.setValue(PointerLoc, PointerVal); 40304eeddc0SDimitry Andric break; 40404eeddc0SDimitry Andric } 40581ad6265SDimitry Andric case UO_LNot: { 40681ad6265SDimitry Andric auto *SubExprVal = 40781ad6265SDimitry Andric dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None)); 40881ad6265SDimitry Andric if (SubExprVal == nullptr) 40981ad6265SDimitry Andric break; 41081ad6265SDimitry Andric 41181ad6265SDimitry Andric auto &ExprLoc = Env.createStorageLocation(*S); 41281ad6265SDimitry Andric Env.setStorageLocation(*S, ExprLoc); 41381ad6265SDimitry Andric Env.setValue(ExprLoc, Env.makeNot(*SubExprVal)); 41481ad6265SDimitry Andric break; 41581ad6265SDimitry Andric } 41604eeddc0SDimitry Andric default: 41704eeddc0SDimitry Andric break; 41804eeddc0SDimitry Andric } 41904eeddc0SDimitry Andric } 42004eeddc0SDimitry Andric 42104eeddc0SDimitry Andric void VisitCXXThisExpr(const CXXThisExpr *S) { 42204eeddc0SDimitry Andric auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); 42381ad6265SDimitry Andric if (ThisPointeeLoc == nullptr) 42481ad6265SDimitry Andric // Unions are not supported yet, and will not have a location for the 42581ad6265SDimitry Andric // `this` expression's pointee. 42681ad6265SDimitry Andric return; 42704eeddc0SDimitry Andric 42804eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 42904eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 43004eeddc0SDimitry Andric Env.setValue(Loc, Env.takeOwnership( 43104eeddc0SDimitry Andric std::make_unique<PointerValue>(*ThisPointeeLoc))); 43204eeddc0SDimitry Andric } 43304eeddc0SDimitry Andric 434*bdd1243dSDimitry Andric void VisitReturnStmt(const ReturnStmt *S) { 435*bdd1243dSDimitry Andric if (!Env.getAnalysisOptions().ContextSensitiveOpts) 436*bdd1243dSDimitry Andric return; 437*bdd1243dSDimitry Andric 438*bdd1243dSDimitry Andric auto *Ret = S->getRetValue(); 439*bdd1243dSDimitry Andric if (Ret == nullptr) 440*bdd1243dSDimitry Andric return; 441*bdd1243dSDimitry Andric 442*bdd1243dSDimitry Andric auto *Val = Env.getValue(*Ret, SkipPast::None); 443*bdd1243dSDimitry Andric if (Val == nullptr) 444*bdd1243dSDimitry Andric return; 445*bdd1243dSDimitry Andric 446*bdd1243dSDimitry Andric // FIXME: Support reference-type returns. 447*bdd1243dSDimitry Andric if (Val->getKind() == Value::Kind::Reference) 448*bdd1243dSDimitry Andric return; 449*bdd1243dSDimitry Andric 450*bdd1243dSDimitry Andric auto *Loc = Env.getReturnStorageLocation(); 451*bdd1243dSDimitry Andric assert(Loc != nullptr); 452*bdd1243dSDimitry Andric // FIXME: Support reference-type returns. 453*bdd1243dSDimitry Andric if (Loc->getType()->isReferenceType()) 454*bdd1243dSDimitry Andric return; 455*bdd1243dSDimitry Andric 456*bdd1243dSDimitry Andric // FIXME: Model NRVO. 457*bdd1243dSDimitry Andric Env.setValue(*Loc, *Val); 458*bdd1243dSDimitry Andric } 459*bdd1243dSDimitry Andric 46004eeddc0SDimitry Andric void VisitMemberExpr(const MemberExpr *S) { 46104eeddc0SDimitry Andric ValueDecl *Member = S->getMemberDecl(); 46204eeddc0SDimitry Andric assert(Member != nullptr); 46304eeddc0SDimitry Andric 46404eeddc0SDimitry Andric // FIXME: Consider assigning pointer values to function member expressions. 46504eeddc0SDimitry Andric if (Member->isFunctionOrFunctionTemplate()) 46604eeddc0SDimitry Andric return; 46704eeddc0SDimitry Andric 468*bdd1243dSDimitry Andric // FIXME: if/when we add support for modeling enums, use that support here. 469*bdd1243dSDimitry Andric if (isa<EnumConstantDecl>(Member)) 470*bdd1243dSDimitry Andric return; 471*bdd1243dSDimitry Andric 47281ad6265SDimitry Andric if (auto *D = dyn_cast<VarDecl>(Member)) { 47381ad6265SDimitry Andric if (D->hasGlobalStorage()) { 47481ad6265SDimitry Andric auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None); 47581ad6265SDimitry Andric if (VarDeclLoc == nullptr) 47681ad6265SDimitry Andric return; 47781ad6265SDimitry Andric 47881ad6265SDimitry Andric if (VarDeclLoc->getType()->isReferenceType()) { 479*bdd1243dSDimitry Andric assert(isa_and_nonnull<ReferenceValue>(Env.getValue((*VarDeclLoc))) && 480*bdd1243dSDimitry Andric "reference-typed declarations map to `ReferenceValue`s"); 48181ad6265SDimitry Andric Env.setStorageLocation(*S, *VarDeclLoc); 48281ad6265SDimitry Andric } else { 48381ad6265SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 48481ad6265SDimitry Andric Env.setStorageLocation(*S, Loc); 48581ad6265SDimitry Andric Env.setValue(Loc, Env.takeOwnership( 48681ad6265SDimitry Andric std::make_unique<ReferenceValue>(*VarDeclLoc))); 48781ad6265SDimitry Andric } 48881ad6265SDimitry Andric return; 48981ad6265SDimitry Andric } 49081ad6265SDimitry Andric } 49181ad6265SDimitry Andric 49204eeddc0SDimitry Andric // The receiver can be either a value or a pointer to a value. Skip past the 49304eeddc0SDimitry Andric // indirection to handle both cases. 49404eeddc0SDimitry Andric auto *BaseLoc = cast_or_null<AggregateStorageLocation>( 49504eeddc0SDimitry Andric Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer)); 49604eeddc0SDimitry Andric if (BaseLoc == nullptr) 49704eeddc0SDimitry Andric return; 49804eeddc0SDimitry Andric 49904eeddc0SDimitry Andric auto &MemberLoc = BaseLoc->getChild(*Member); 50004eeddc0SDimitry Andric if (MemberLoc.getType()->isReferenceType()) { 501*bdd1243dSDimitry Andric // Based on its type, `MemberLoc` must be mapped either to nothing or to a 502*bdd1243dSDimitry Andric // `ReferenceValue`. For the former, we won't set a storage location for 503*bdd1243dSDimitry Andric // this expression, so as to maintain an invariant lvalue expressions; 504*bdd1243dSDimitry Andric // namely, that their location maps to a `ReferenceValue`. In this, 505*bdd1243dSDimitry Andric // lvalues are unlike other expressions, where it is valid for their 506*bdd1243dSDimitry Andric // location to map to nothing (because they are not modeled). 507*bdd1243dSDimitry Andric // 508*bdd1243dSDimitry Andric // Note: we need this invariant for lvalues so that, when accessing a 509*bdd1243dSDimitry Andric // value, we can distinguish an rvalue from an lvalue. An alternative 510*bdd1243dSDimitry Andric // design, which takes the expression's value category into account, would 511*bdd1243dSDimitry Andric // avoid the need for this invariant. 512*bdd1243dSDimitry Andric if (auto *V = Env.getValue(MemberLoc)) { 513*bdd1243dSDimitry Andric assert(isa<ReferenceValue>(V) && 514*bdd1243dSDimitry Andric "reference-typed declarations map to `ReferenceValue`s"); 51504eeddc0SDimitry Andric Env.setStorageLocation(*S, MemberLoc); 516*bdd1243dSDimitry Andric } 51704eeddc0SDimitry Andric } else { 51804eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 51904eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 52004eeddc0SDimitry Andric Env.setValue( 52104eeddc0SDimitry Andric Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc))); 52204eeddc0SDimitry Andric } 52304eeddc0SDimitry Andric } 52404eeddc0SDimitry Andric 52504eeddc0SDimitry Andric void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { 52604eeddc0SDimitry Andric const Expr *InitExpr = S->getExpr(); 52704eeddc0SDimitry Andric assert(InitExpr != nullptr); 52804eeddc0SDimitry Andric 52904eeddc0SDimitry Andric Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None); 53004eeddc0SDimitry Andric if (InitExprVal == nullptr) 53104eeddc0SDimitry Andric return; 53204eeddc0SDimitry Andric 53304eeddc0SDimitry Andric const FieldDecl *Field = S->getField(); 53404eeddc0SDimitry Andric assert(Field != nullptr); 53504eeddc0SDimitry Andric 53604eeddc0SDimitry Andric auto &ThisLoc = 53704eeddc0SDimitry Andric *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation()); 53804eeddc0SDimitry Andric auto &FieldLoc = ThisLoc.getChild(*Field); 53904eeddc0SDimitry Andric Env.setValue(FieldLoc, *InitExprVal); 54004eeddc0SDimitry Andric } 54104eeddc0SDimitry Andric 54204eeddc0SDimitry Andric void VisitCXXConstructExpr(const CXXConstructExpr *S) { 54304eeddc0SDimitry Andric const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); 54404eeddc0SDimitry Andric assert(ConstructorDecl != nullptr); 54504eeddc0SDimitry Andric 54604eeddc0SDimitry Andric if (ConstructorDecl->isCopyOrMoveConstructor()) { 54704eeddc0SDimitry Andric assert(S->getNumArgs() == 1); 54804eeddc0SDimitry Andric 54904eeddc0SDimitry Andric const Expr *Arg = S->getArg(0); 55004eeddc0SDimitry Andric assert(Arg != nullptr); 55104eeddc0SDimitry Andric 55204eeddc0SDimitry Andric if (S->isElidable()) { 55304eeddc0SDimitry Andric auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference); 55404eeddc0SDimitry Andric if (ArgLoc == nullptr) 55504eeddc0SDimitry Andric return; 55604eeddc0SDimitry Andric 55704eeddc0SDimitry Andric Env.setStorageLocation(*S, *ArgLoc); 55804eeddc0SDimitry Andric } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) { 55904eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 56004eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 56104eeddc0SDimitry Andric Env.setValue(Loc, *ArgVal); 56204eeddc0SDimitry Andric } 56304eeddc0SDimitry Andric return; 56404eeddc0SDimitry Andric } 56504eeddc0SDimitry Andric 56604eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 56704eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 56804eeddc0SDimitry Andric if (Value *Val = Env.createValue(S->getType())) 56904eeddc0SDimitry Andric Env.setValue(Loc, *Val); 570*bdd1243dSDimitry Andric 571*bdd1243dSDimitry Andric transferInlineCall(S, ConstructorDecl); 57204eeddc0SDimitry Andric } 57304eeddc0SDimitry Andric 57404eeddc0SDimitry Andric void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { 57504eeddc0SDimitry Andric if (S->getOperator() == OO_Equal) { 57604eeddc0SDimitry Andric assert(S->getNumArgs() == 2); 57704eeddc0SDimitry Andric 57804eeddc0SDimitry Andric const Expr *Arg0 = S->getArg(0); 57904eeddc0SDimitry Andric assert(Arg0 != nullptr); 58004eeddc0SDimitry Andric 58104eeddc0SDimitry Andric const Expr *Arg1 = S->getArg(1); 58204eeddc0SDimitry Andric assert(Arg1 != nullptr); 58304eeddc0SDimitry Andric 58404eeddc0SDimitry Andric // Evaluate only copy and move assignment operators. 58504eeddc0SDimitry Andric auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType(); 58604eeddc0SDimitry Andric auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType(); 58704eeddc0SDimitry Andric if (Arg0Type != Arg1Type) 58804eeddc0SDimitry Andric return; 58904eeddc0SDimitry Andric 59004eeddc0SDimitry Andric auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference); 59104eeddc0SDimitry Andric if (ObjectLoc == nullptr) 59204eeddc0SDimitry Andric return; 59304eeddc0SDimitry Andric 59404eeddc0SDimitry Andric auto *Val = Env.getValue(*Arg1, SkipPast::Reference); 59504eeddc0SDimitry Andric if (Val == nullptr) 59604eeddc0SDimitry Andric return; 59704eeddc0SDimitry Andric 59881ad6265SDimitry Andric // Assign a value to the storage location of the object. 59904eeddc0SDimitry Andric Env.setValue(*ObjectLoc, *Val); 60081ad6265SDimitry Andric 60181ad6265SDimitry Andric // FIXME: Add a test for the value of the whole expression. 60281ad6265SDimitry Andric // Assign a storage location for the whole expression. 60381ad6265SDimitry Andric Env.setStorageLocation(*S, *ObjectLoc); 60404eeddc0SDimitry Andric } 60504eeddc0SDimitry Andric } 60604eeddc0SDimitry Andric 60704eeddc0SDimitry Andric void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { 60804eeddc0SDimitry Andric if (S->getCastKind() == CK_ConstructorConversion) { 60904eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 61004eeddc0SDimitry Andric assert(SubExpr != nullptr); 61104eeddc0SDimitry Andric 61204eeddc0SDimitry Andric auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 61304eeddc0SDimitry Andric if (SubExprLoc == nullptr) 61404eeddc0SDimitry Andric return; 61504eeddc0SDimitry Andric 61604eeddc0SDimitry Andric Env.setStorageLocation(*S, *SubExprLoc); 61704eeddc0SDimitry Andric } 61804eeddc0SDimitry Andric } 61904eeddc0SDimitry Andric 62004eeddc0SDimitry Andric void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { 62104eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 62204eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 62304eeddc0SDimitry Andric if (Value *Val = Env.createValue(S->getType())) 62404eeddc0SDimitry Andric Env.setValue(Loc, *Val); 62504eeddc0SDimitry Andric } 62604eeddc0SDimitry Andric 62704eeddc0SDimitry Andric void VisitCallExpr(const CallExpr *S) { 62881ad6265SDimitry Andric // Of clang's builtins, only `__builtin_expect` is handled explicitly, since 62981ad6265SDimitry Andric // others (like trap, debugtrap, and unreachable) are handled by CFG 63081ad6265SDimitry Andric // construction. 63104eeddc0SDimitry Andric if (S->isCallToStdMove()) { 63204eeddc0SDimitry Andric assert(S->getNumArgs() == 1); 63304eeddc0SDimitry Andric 63404eeddc0SDimitry Andric const Expr *Arg = S->getArg(0); 63504eeddc0SDimitry Andric assert(Arg != nullptr); 63604eeddc0SDimitry Andric 63704eeddc0SDimitry Andric auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None); 63804eeddc0SDimitry Andric if (ArgLoc == nullptr) 63904eeddc0SDimitry Andric return; 64004eeddc0SDimitry Andric 64104eeddc0SDimitry Andric Env.setStorageLocation(*S, *ArgLoc); 64281ad6265SDimitry Andric } else if (S->getDirectCallee() != nullptr && 64381ad6265SDimitry Andric S->getDirectCallee()->getBuiltinID() == 64481ad6265SDimitry Andric Builtin::BI__builtin_expect) { 64581ad6265SDimitry Andric assert(S->getNumArgs() > 0); 64681ad6265SDimitry Andric assert(S->getArg(0) != nullptr); 64781ad6265SDimitry Andric // `__builtin_expect` returns by-value, so strip away any potential 64881ad6265SDimitry Andric // references in the argument. 64981ad6265SDimitry Andric auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference); 65081ad6265SDimitry Andric if (ArgLoc == nullptr) 65181ad6265SDimitry Andric return; 65281ad6265SDimitry Andric Env.setStorageLocation(*S, *ArgLoc); 653972a253aSDimitry Andric } else if (const FunctionDecl *F = S->getDirectCallee()) { 654*bdd1243dSDimitry Andric transferInlineCall(S, F); 65504eeddc0SDimitry Andric } 65604eeddc0SDimitry Andric } 65704eeddc0SDimitry Andric 65804eeddc0SDimitry Andric void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { 65904eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 66004eeddc0SDimitry Andric assert(SubExpr != nullptr); 66104eeddc0SDimitry Andric 66204eeddc0SDimitry Andric auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 66304eeddc0SDimitry Andric if (SubExprLoc == nullptr) 66404eeddc0SDimitry Andric return; 66504eeddc0SDimitry Andric 66604eeddc0SDimitry Andric Env.setStorageLocation(*S, *SubExprLoc); 66704eeddc0SDimitry Andric } 66804eeddc0SDimitry Andric 66904eeddc0SDimitry Andric void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { 67004eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 67104eeddc0SDimitry Andric assert(SubExpr != nullptr); 67204eeddc0SDimitry Andric 67304eeddc0SDimitry Andric auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 67404eeddc0SDimitry Andric if (SubExprLoc == nullptr) 67504eeddc0SDimitry Andric return; 67604eeddc0SDimitry Andric 67704eeddc0SDimitry Andric Env.setStorageLocation(*S, *SubExprLoc); 67804eeddc0SDimitry Andric } 67904eeddc0SDimitry Andric 68004eeddc0SDimitry Andric void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { 68104eeddc0SDimitry Andric if (S->getCastKind() == CK_NoOp) { 68204eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 68304eeddc0SDimitry Andric assert(SubExpr != nullptr); 68404eeddc0SDimitry Andric 68504eeddc0SDimitry Andric auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 68604eeddc0SDimitry Andric if (SubExprLoc == nullptr) 68704eeddc0SDimitry Andric return; 68804eeddc0SDimitry Andric 68904eeddc0SDimitry Andric Env.setStorageLocation(*S, *SubExprLoc); 69004eeddc0SDimitry Andric } 69104eeddc0SDimitry Andric } 69204eeddc0SDimitry Andric 69304eeddc0SDimitry Andric void VisitConditionalOperator(const ConditionalOperator *S) { 69404eeddc0SDimitry Andric // FIXME: Revisit this once flow conditions are added to the framework. For 69504eeddc0SDimitry Andric // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow 69604eeddc0SDimitry Andric // condition. 69704eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 69804eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 69904eeddc0SDimitry Andric if (Value *Val = Env.createValue(S->getType())) 70004eeddc0SDimitry Andric Env.setValue(Loc, *Val); 70104eeddc0SDimitry Andric } 70204eeddc0SDimitry Andric 70304eeddc0SDimitry Andric void VisitInitListExpr(const InitListExpr *S) { 70404eeddc0SDimitry Andric QualType Type = S->getType(); 70504eeddc0SDimitry Andric 70604eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 70704eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 70804eeddc0SDimitry Andric 70904eeddc0SDimitry Andric auto *Val = Env.createValue(Type); 71004eeddc0SDimitry Andric if (Val == nullptr) 71104eeddc0SDimitry Andric return; 71204eeddc0SDimitry Andric 71304eeddc0SDimitry Andric Env.setValue(Loc, *Val); 71404eeddc0SDimitry Andric 71504eeddc0SDimitry Andric if (Type->isStructureOrClassType()) { 716972a253aSDimitry Andric for (auto It : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) { 717972a253aSDimitry Andric const FieldDecl *Field = std::get<0>(It); 71804eeddc0SDimitry Andric assert(Field != nullptr); 71904eeddc0SDimitry Andric 720972a253aSDimitry Andric const Expr *Init = std::get<1>(It); 72104eeddc0SDimitry Andric assert(Init != nullptr); 72204eeddc0SDimitry Andric 72304eeddc0SDimitry Andric if (Value *InitVal = Env.getValue(*Init, SkipPast::None)) 72404eeddc0SDimitry Andric cast<StructValue>(Val)->setChild(*Field, *InitVal); 72504eeddc0SDimitry Andric } 72604eeddc0SDimitry Andric } 72704eeddc0SDimitry Andric // FIXME: Implement array initialization. 72804eeddc0SDimitry Andric } 72904eeddc0SDimitry Andric 73004eeddc0SDimitry Andric void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { 73104eeddc0SDimitry Andric auto &Loc = Env.createStorageLocation(*S); 73204eeddc0SDimitry Andric Env.setStorageLocation(*S, Loc); 73304eeddc0SDimitry Andric Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue())); 73404eeddc0SDimitry Andric } 73504eeddc0SDimitry Andric 73681ad6265SDimitry Andric void VisitParenExpr(const ParenExpr *S) { 73781ad6265SDimitry Andric // The CFG does not contain `ParenExpr` as top-level statements in basic 73881ad6265SDimitry Andric // blocks, however manual traversal to sub-expressions may encounter them. 73981ad6265SDimitry Andric // Redirect to the sub-expression. 74081ad6265SDimitry Andric auto *SubExpr = S->getSubExpr(); 74181ad6265SDimitry Andric assert(SubExpr != nullptr); 74281ad6265SDimitry Andric Visit(SubExpr); 74381ad6265SDimitry Andric } 74481ad6265SDimitry Andric 74581ad6265SDimitry Andric void VisitExprWithCleanups(const ExprWithCleanups *S) { 74681ad6265SDimitry Andric // The CFG does not contain `ExprWithCleanups` as top-level statements in 74781ad6265SDimitry Andric // basic blocks, however manual traversal to sub-expressions may encounter 74881ad6265SDimitry Andric // them. Redirect to the sub-expression. 74981ad6265SDimitry Andric auto *SubExpr = S->getSubExpr(); 75081ad6265SDimitry Andric assert(SubExpr != nullptr); 75181ad6265SDimitry Andric Visit(SubExpr); 75281ad6265SDimitry Andric } 75381ad6265SDimitry Andric 75404eeddc0SDimitry Andric private: 75581ad6265SDimitry Andric BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { 75681ad6265SDimitry Andric // `SubExpr` and its parent logic operator might be part of different basic 75781ad6265SDimitry Andric // blocks. We try to access the value that is assigned to `SubExpr` in the 75881ad6265SDimitry Andric // corresponding environment. 75981ad6265SDimitry Andric if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) { 76081ad6265SDimitry Andric if (auto *Val = dyn_cast_or_null<BoolValue>( 76181ad6265SDimitry Andric SubExprEnv->getValue(SubExpr, SkipPast::Reference))) 76281ad6265SDimitry Andric return *Val; 76381ad6265SDimitry Andric } 76481ad6265SDimitry Andric 76581ad6265SDimitry Andric if (Env.getStorageLocation(SubExpr, SkipPast::None) == nullptr) { 76681ad6265SDimitry Andric // Sub-expressions that are logic operators are not added in basic blocks 76781ad6265SDimitry Andric // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic 76881ad6265SDimitry Andric // operator, it may not have been evaluated and assigned a value yet. In 76981ad6265SDimitry Andric // that case, we need to first visit `SubExpr` and then try to get the 77081ad6265SDimitry Andric // value that gets assigned to it. 77181ad6265SDimitry Andric Visit(&SubExpr); 77281ad6265SDimitry Andric } 77381ad6265SDimitry Andric 77481ad6265SDimitry Andric if (auto *Val = dyn_cast_or_null<BoolValue>( 77581ad6265SDimitry Andric Env.getValue(SubExpr, SkipPast::Reference))) 77681ad6265SDimitry Andric return *Val; 77781ad6265SDimitry Andric 77881ad6265SDimitry Andric // If the value of `SubExpr` is still unknown, we create a fresh symbolic 77981ad6265SDimitry Andric // boolean value for it. 78081ad6265SDimitry Andric return Env.makeAtomicBoolValue(); 78181ad6265SDimitry Andric } 78281ad6265SDimitry Andric 783*bdd1243dSDimitry Andric // If context sensitivity is enabled, try to analyze the body of the callee 784*bdd1243dSDimitry Andric // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`. 785*bdd1243dSDimitry Andric template <typename E> 786*bdd1243dSDimitry Andric void transferInlineCall(const E *S, const FunctionDecl *F) { 787*bdd1243dSDimitry Andric const auto &Options = Env.getAnalysisOptions(); 788*bdd1243dSDimitry Andric if (!(Options.ContextSensitiveOpts && 789*bdd1243dSDimitry Andric Env.canDescend(Options.ContextSensitiveOpts->Depth, F))) 790*bdd1243dSDimitry Andric return; 791*bdd1243dSDimitry Andric 792*bdd1243dSDimitry Andric const ControlFlowContext *CFCtx = Env.getControlFlowContext(F); 793*bdd1243dSDimitry Andric if (!CFCtx) 794*bdd1243dSDimitry Andric return; 795*bdd1243dSDimitry Andric 796*bdd1243dSDimitry Andric // FIXME: We don't support context-sensitive analysis of recursion, so 797*bdd1243dSDimitry Andric // we should return early here if `F` is the same as the `FunctionDecl` 798*bdd1243dSDimitry Andric // holding `S` itself. 799*bdd1243dSDimitry Andric 800*bdd1243dSDimitry Andric auto ExitBlock = CFCtx->getCFG().getExit().getBlockID(); 801*bdd1243dSDimitry Andric 802*bdd1243dSDimitry Andric if (const auto *NonConstructExpr = dyn_cast<CallExpr>(S)) { 803*bdd1243dSDimitry Andric // Note that it is important for the storage location of `S` to be set 804*bdd1243dSDimitry Andric // before `pushCall`, because the latter uses it to set the storage 805*bdd1243dSDimitry Andric // location for `return`. 806*bdd1243dSDimitry Andric auto &ReturnLoc = Env.createStorageLocation(*S); 807*bdd1243dSDimitry Andric Env.setStorageLocation(*S, ReturnLoc); 808*bdd1243dSDimitry Andric } 809*bdd1243dSDimitry Andric auto CalleeEnv = Env.pushCall(S); 810*bdd1243dSDimitry Andric 811*bdd1243dSDimitry Andric // FIXME: Use the same analysis as the caller for the callee. Note, 812*bdd1243dSDimitry Andric // though, that doing so would require support for changing the analysis's 813*bdd1243dSDimitry Andric // ASTContext. 814*bdd1243dSDimitry Andric assert(CFCtx->getDecl() != nullptr && 815*bdd1243dSDimitry Andric "ControlFlowContexts in the environment should always carry a decl"); 816*bdd1243dSDimitry Andric auto Analysis = NoopAnalysis(CFCtx->getDecl()->getASTContext(), 817*bdd1243dSDimitry Andric DataflowAnalysisOptions{Options}); 818*bdd1243dSDimitry Andric 819*bdd1243dSDimitry Andric auto BlockToOutputState = 820*bdd1243dSDimitry Andric dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv); 821*bdd1243dSDimitry Andric assert(BlockToOutputState); 822*bdd1243dSDimitry Andric assert(ExitBlock < BlockToOutputState->size()); 823*bdd1243dSDimitry Andric 824*bdd1243dSDimitry Andric auto ExitState = (*BlockToOutputState)[ExitBlock]; 825*bdd1243dSDimitry Andric assert(ExitState); 826*bdd1243dSDimitry Andric 827*bdd1243dSDimitry Andric Env.popCall(ExitState->Env); 828*bdd1243dSDimitry Andric } 829*bdd1243dSDimitry Andric 83081ad6265SDimitry Andric const StmtToEnvMap &StmtToEnv; 83104eeddc0SDimitry Andric Environment &Env; 83204eeddc0SDimitry Andric }; 83304eeddc0SDimitry Andric 834*bdd1243dSDimitry Andric void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { 835*bdd1243dSDimitry Andric TransferVisitor(StmtToEnv, Env).Visit(&S); 83604eeddc0SDimitry Andric } 83704eeddc0SDimitry Andric 83804eeddc0SDimitry Andric } // namespace dataflow 83904eeddc0SDimitry Andric } // namespace clang 840