1*81ad6265SDimitry Andric //===-- DataflowAnalysisContext.cpp -----------------------------*- C++ -*-===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This file defines a DataflowAnalysisContext class that owns objects that 10*81ad6265SDimitry Andric // encompass the state of a program and stores context that is used during 11*81ad6265SDimitry Andric // dataflow analysis. 12*81ad6265SDimitry Andric // 13*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 14*81ad6265SDimitry Andric 15*81ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 16*81ad6265SDimitry Andric #include "clang/AST/ExprCXX.h" 17*81ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 18*81ad6265SDimitry Andric #include <cassert> 19*81ad6265SDimitry Andric #include <memory> 20*81ad6265SDimitry Andric #include <utility> 21*81ad6265SDimitry Andric 22*81ad6265SDimitry Andric namespace clang { 23*81ad6265SDimitry Andric namespace dataflow { 24*81ad6265SDimitry Andric 25*81ad6265SDimitry Andric StorageLocation & 26*81ad6265SDimitry Andric DataflowAnalysisContext::getStableStorageLocation(QualType Type) { 27*81ad6265SDimitry Andric assert(!Type.isNull()); 28*81ad6265SDimitry Andric if (Type->isStructureOrClassType() || Type->isUnionType()) { 29*81ad6265SDimitry Andric // FIXME: Explore options to avoid eager initialization of fields as some of 30*81ad6265SDimitry Andric // them might not be needed for a particular analysis. 31*81ad6265SDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 32*81ad6265SDimitry Andric for (const FieldDecl *Field : getObjectFields(Type)) 33*81ad6265SDimitry Andric FieldLocs.insert({Field, &getStableStorageLocation(Field->getType())}); 34*81ad6265SDimitry Andric return takeOwnership( 35*81ad6265SDimitry Andric std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs))); 36*81ad6265SDimitry Andric } 37*81ad6265SDimitry Andric return takeOwnership(std::make_unique<ScalarStorageLocation>(Type)); 38*81ad6265SDimitry Andric } 39*81ad6265SDimitry Andric 40*81ad6265SDimitry Andric StorageLocation & 41*81ad6265SDimitry Andric DataflowAnalysisContext::getStableStorageLocation(const VarDecl &D) { 42*81ad6265SDimitry Andric if (auto *Loc = getStorageLocation(D)) 43*81ad6265SDimitry Andric return *Loc; 44*81ad6265SDimitry Andric auto &Loc = getStableStorageLocation(D.getType()); 45*81ad6265SDimitry Andric setStorageLocation(D, Loc); 46*81ad6265SDimitry Andric return Loc; 47*81ad6265SDimitry Andric } 48*81ad6265SDimitry Andric 49*81ad6265SDimitry Andric StorageLocation & 50*81ad6265SDimitry Andric DataflowAnalysisContext::getStableStorageLocation(const Expr &E) { 51*81ad6265SDimitry Andric if (auto *Loc = getStorageLocation(E)) 52*81ad6265SDimitry Andric return *Loc; 53*81ad6265SDimitry Andric auto &Loc = getStableStorageLocation(E.getType()); 54*81ad6265SDimitry Andric setStorageLocation(E, Loc); 55*81ad6265SDimitry Andric return Loc; 56*81ad6265SDimitry Andric } 57*81ad6265SDimitry Andric 58*81ad6265SDimitry Andric PointerValue & 59*81ad6265SDimitry Andric DataflowAnalysisContext::getOrCreateNullPointerValue(QualType PointeeType) { 60*81ad6265SDimitry Andric assert(!PointeeType.isNull()); 61*81ad6265SDimitry Andric auto CanonicalPointeeType = PointeeType.getCanonicalType(); 62*81ad6265SDimitry Andric auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr); 63*81ad6265SDimitry Andric if (Res.second) { 64*81ad6265SDimitry Andric auto &PointeeLoc = getStableStorageLocation(CanonicalPointeeType); 65*81ad6265SDimitry Andric Res.first->second = 66*81ad6265SDimitry Andric &takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); 67*81ad6265SDimitry Andric } 68*81ad6265SDimitry Andric return *Res.first->second; 69*81ad6265SDimitry Andric } 70*81ad6265SDimitry Andric 71*81ad6265SDimitry Andric static std::pair<BoolValue *, BoolValue *> 72*81ad6265SDimitry Andric makeCanonicalBoolValuePair(BoolValue &LHS, BoolValue &RHS) { 73*81ad6265SDimitry Andric auto Res = std::make_pair(&LHS, &RHS); 74*81ad6265SDimitry Andric if (&RHS < &LHS) 75*81ad6265SDimitry Andric std::swap(Res.first, Res.second); 76*81ad6265SDimitry Andric return Res; 77*81ad6265SDimitry Andric } 78*81ad6265SDimitry Andric 79*81ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateConjunction(BoolValue &LHS, 80*81ad6265SDimitry Andric BoolValue &RHS) { 81*81ad6265SDimitry Andric if (&LHS == &RHS) 82*81ad6265SDimitry Andric return LHS; 83*81ad6265SDimitry Andric 84*81ad6265SDimitry Andric auto Res = ConjunctionVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS), 85*81ad6265SDimitry Andric nullptr); 86*81ad6265SDimitry Andric if (Res.second) 87*81ad6265SDimitry Andric Res.first->second = 88*81ad6265SDimitry Andric &takeOwnership(std::make_unique<ConjunctionValue>(LHS, RHS)); 89*81ad6265SDimitry Andric return *Res.first->second; 90*81ad6265SDimitry Andric } 91*81ad6265SDimitry Andric 92*81ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateDisjunction(BoolValue &LHS, 93*81ad6265SDimitry Andric BoolValue &RHS) { 94*81ad6265SDimitry Andric if (&LHS == &RHS) 95*81ad6265SDimitry Andric return LHS; 96*81ad6265SDimitry Andric 97*81ad6265SDimitry Andric auto Res = DisjunctionVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS), 98*81ad6265SDimitry Andric nullptr); 99*81ad6265SDimitry Andric if (Res.second) 100*81ad6265SDimitry Andric Res.first->second = 101*81ad6265SDimitry Andric &takeOwnership(std::make_unique<DisjunctionValue>(LHS, RHS)); 102*81ad6265SDimitry Andric return *Res.first->second; 103*81ad6265SDimitry Andric } 104*81ad6265SDimitry Andric 105*81ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateNegation(BoolValue &Val) { 106*81ad6265SDimitry Andric auto Res = NegationVals.try_emplace(&Val, nullptr); 107*81ad6265SDimitry Andric if (Res.second) 108*81ad6265SDimitry Andric Res.first->second = &takeOwnership(std::make_unique<NegationValue>(Val)); 109*81ad6265SDimitry Andric return *Res.first->second; 110*81ad6265SDimitry Andric } 111*81ad6265SDimitry Andric 112*81ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateImplication(BoolValue &LHS, 113*81ad6265SDimitry Andric BoolValue &RHS) { 114*81ad6265SDimitry Andric return &LHS == &RHS ? getBoolLiteralValue(true) 115*81ad6265SDimitry Andric : getOrCreateDisjunction(getOrCreateNegation(LHS), RHS); 116*81ad6265SDimitry Andric } 117*81ad6265SDimitry Andric 118*81ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateIff(BoolValue &LHS, 119*81ad6265SDimitry Andric BoolValue &RHS) { 120*81ad6265SDimitry Andric return &LHS == &RHS 121*81ad6265SDimitry Andric ? getBoolLiteralValue(true) 122*81ad6265SDimitry Andric : getOrCreateConjunction(getOrCreateImplication(LHS, RHS), 123*81ad6265SDimitry Andric getOrCreateImplication(RHS, LHS)); 124*81ad6265SDimitry Andric } 125*81ad6265SDimitry Andric 126*81ad6265SDimitry Andric AtomicBoolValue &DataflowAnalysisContext::makeFlowConditionToken() { 127*81ad6265SDimitry Andric return createAtomicBoolValue(); 128*81ad6265SDimitry Andric } 129*81ad6265SDimitry Andric 130*81ad6265SDimitry Andric void DataflowAnalysisContext::addFlowConditionConstraint( 131*81ad6265SDimitry Andric AtomicBoolValue &Token, BoolValue &Constraint) { 132*81ad6265SDimitry Andric auto Res = FlowConditionConstraints.try_emplace(&Token, &Constraint); 133*81ad6265SDimitry Andric if (!Res.second) { 134*81ad6265SDimitry Andric Res.first->second = &getOrCreateConjunction(*Res.first->second, Constraint); 135*81ad6265SDimitry Andric } 136*81ad6265SDimitry Andric } 137*81ad6265SDimitry Andric 138*81ad6265SDimitry Andric AtomicBoolValue & 139*81ad6265SDimitry Andric DataflowAnalysisContext::forkFlowCondition(AtomicBoolValue &Token) { 140*81ad6265SDimitry Andric auto &ForkToken = makeFlowConditionToken(); 141*81ad6265SDimitry Andric FlowConditionDeps[&ForkToken].insert(&Token); 142*81ad6265SDimitry Andric addFlowConditionConstraint(ForkToken, Token); 143*81ad6265SDimitry Andric return ForkToken; 144*81ad6265SDimitry Andric } 145*81ad6265SDimitry Andric 146*81ad6265SDimitry Andric AtomicBoolValue & 147*81ad6265SDimitry Andric DataflowAnalysisContext::joinFlowConditions(AtomicBoolValue &FirstToken, 148*81ad6265SDimitry Andric AtomicBoolValue &SecondToken) { 149*81ad6265SDimitry Andric auto &Token = makeFlowConditionToken(); 150*81ad6265SDimitry Andric FlowConditionDeps[&Token].insert(&FirstToken); 151*81ad6265SDimitry Andric FlowConditionDeps[&Token].insert(&SecondToken); 152*81ad6265SDimitry Andric addFlowConditionConstraint(Token, 153*81ad6265SDimitry Andric getOrCreateDisjunction(FirstToken, SecondToken)); 154*81ad6265SDimitry Andric return Token; 155*81ad6265SDimitry Andric } 156*81ad6265SDimitry Andric 157*81ad6265SDimitry Andric Solver::Result 158*81ad6265SDimitry Andric DataflowAnalysisContext::querySolver(llvm::DenseSet<BoolValue *> Constraints) { 159*81ad6265SDimitry Andric Constraints.insert(&getBoolLiteralValue(true)); 160*81ad6265SDimitry Andric Constraints.insert(&getOrCreateNegation(getBoolLiteralValue(false))); 161*81ad6265SDimitry Andric return S->solve(std::move(Constraints)); 162*81ad6265SDimitry Andric } 163*81ad6265SDimitry Andric 164*81ad6265SDimitry Andric bool DataflowAnalysisContext::flowConditionImplies(AtomicBoolValue &Token, 165*81ad6265SDimitry Andric BoolValue &Val) { 166*81ad6265SDimitry Andric // Returns true if and only if truth assignment of the flow condition implies 167*81ad6265SDimitry Andric // that `Val` is also true. We prove whether or not this property holds by 168*81ad6265SDimitry Andric // reducing the problem to satisfiability checking. In other words, we attempt 169*81ad6265SDimitry Andric // to show that assuming `Val` is false makes the constraints induced by the 170*81ad6265SDimitry Andric // flow condition unsatisfiable. 171*81ad6265SDimitry Andric llvm::DenseSet<BoolValue *> Constraints = {&Token, &getOrCreateNegation(Val)}; 172*81ad6265SDimitry Andric llvm::DenseSet<AtomicBoolValue *> VisitedTokens; 173*81ad6265SDimitry Andric addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); 174*81ad6265SDimitry Andric return isUnsatisfiable(std::move(Constraints)); 175*81ad6265SDimitry Andric } 176*81ad6265SDimitry Andric 177*81ad6265SDimitry Andric bool DataflowAnalysisContext::flowConditionIsTautology(AtomicBoolValue &Token) { 178*81ad6265SDimitry Andric // Returns true if and only if we cannot prove that the flow condition can 179*81ad6265SDimitry Andric // ever be false. 180*81ad6265SDimitry Andric llvm::DenseSet<BoolValue *> Constraints = {&getOrCreateNegation(Token)}; 181*81ad6265SDimitry Andric llvm::DenseSet<AtomicBoolValue *> VisitedTokens; 182*81ad6265SDimitry Andric addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); 183*81ad6265SDimitry Andric return isUnsatisfiable(std::move(Constraints)); 184*81ad6265SDimitry Andric } 185*81ad6265SDimitry Andric 186*81ad6265SDimitry Andric bool DataflowAnalysisContext::equivalentBoolValues(BoolValue &Val1, 187*81ad6265SDimitry Andric BoolValue &Val2) { 188*81ad6265SDimitry Andric llvm::DenseSet<BoolValue *> Constraints = { 189*81ad6265SDimitry Andric &getOrCreateNegation(getOrCreateIff(Val1, Val2))}; 190*81ad6265SDimitry Andric return isUnsatisfiable(Constraints); 191*81ad6265SDimitry Andric } 192*81ad6265SDimitry Andric 193*81ad6265SDimitry Andric void DataflowAnalysisContext::addTransitiveFlowConditionConstraints( 194*81ad6265SDimitry Andric AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints, 195*81ad6265SDimitry Andric llvm::DenseSet<AtomicBoolValue *> &VisitedTokens) { 196*81ad6265SDimitry Andric auto Res = VisitedTokens.insert(&Token); 197*81ad6265SDimitry Andric if (!Res.second) 198*81ad6265SDimitry Andric return; 199*81ad6265SDimitry Andric 200*81ad6265SDimitry Andric auto ConstraintsIT = FlowConditionConstraints.find(&Token); 201*81ad6265SDimitry Andric if (ConstraintsIT == FlowConditionConstraints.end()) { 202*81ad6265SDimitry Andric Constraints.insert(&Token); 203*81ad6265SDimitry Andric } else { 204*81ad6265SDimitry Andric // Bind flow condition token via `iff` to its set of constraints: 205*81ad6265SDimitry Andric // FC <=> (C1 ^ C2 ^ ...), where Ci are constraints 206*81ad6265SDimitry Andric Constraints.insert(&getOrCreateIff(Token, *ConstraintsIT->second)); 207*81ad6265SDimitry Andric } 208*81ad6265SDimitry Andric 209*81ad6265SDimitry Andric auto DepsIT = FlowConditionDeps.find(&Token); 210*81ad6265SDimitry Andric if (DepsIT != FlowConditionDeps.end()) { 211*81ad6265SDimitry Andric for (AtomicBoolValue *DepToken : DepsIT->second) { 212*81ad6265SDimitry Andric addTransitiveFlowConditionConstraints(*DepToken, Constraints, 213*81ad6265SDimitry Andric VisitedTokens); 214*81ad6265SDimitry Andric } 215*81ad6265SDimitry Andric } 216*81ad6265SDimitry Andric } 217*81ad6265SDimitry Andric 218*81ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::substituteBoolValue( 219*81ad6265SDimitry Andric BoolValue &Val, 220*81ad6265SDimitry Andric llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) { 221*81ad6265SDimitry Andric auto IT = SubstitutionsCache.find(&Val); 222*81ad6265SDimitry Andric if (IT != SubstitutionsCache.end()) { 223*81ad6265SDimitry Andric // Return memoized result of substituting this boolean value. 224*81ad6265SDimitry Andric return *IT->second; 225*81ad6265SDimitry Andric } 226*81ad6265SDimitry Andric 227*81ad6265SDimitry Andric // Handle substitution on the boolean value (and its subvalues), saving the 228*81ad6265SDimitry Andric // result into `SubstitutionsCache`. 229*81ad6265SDimitry Andric BoolValue *Result; 230*81ad6265SDimitry Andric switch (Val.getKind()) { 231*81ad6265SDimitry Andric case Value::Kind::AtomicBool: { 232*81ad6265SDimitry Andric Result = &Val; 233*81ad6265SDimitry Andric break; 234*81ad6265SDimitry Andric } 235*81ad6265SDimitry Andric case Value::Kind::Negation: { 236*81ad6265SDimitry Andric auto &Negation = *cast<NegationValue>(&Val); 237*81ad6265SDimitry Andric auto &Sub = substituteBoolValue(Negation.getSubVal(), SubstitutionsCache); 238*81ad6265SDimitry Andric Result = &getOrCreateNegation(Sub); 239*81ad6265SDimitry Andric break; 240*81ad6265SDimitry Andric } 241*81ad6265SDimitry Andric case Value::Kind::Disjunction: { 242*81ad6265SDimitry Andric auto &Disjunct = *cast<DisjunctionValue>(&Val); 243*81ad6265SDimitry Andric auto &LeftSub = 244*81ad6265SDimitry Andric substituteBoolValue(Disjunct.getLeftSubValue(), SubstitutionsCache); 245*81ad6265SDimitry Andric auto &RightSub = 246*81ad6265SDimitry Andric substituteBoolValue(Disjunct.getRightSubValue(), SubstitutionsCache); 247*81ad6265SDimitry Andric Result = &getOrCreateDisjunction(LeftSub, RightSub); 248*81ad6265SDimitry Andric break; 249*81ad6265SDimitry Andric } 250*81ad6265SDimitry Andric case Value::Kind::Conjunction: { 251*81ad6265SDimitry Andric auto &Conjunct = *cast<ConjunctionValue>(&Val); 252*81ad6265SDimitry Andric auto &LeftSub = 253*81ad6265SDimitry Andric substituteBoolValue(Conjunct.getLeftSubValue(), SubstitutionsCache); 254*81ad6265SDimitry Andric auto &RightSub = 255*81ad6265SDimitry Andric substituteBoolValue(Conjunct.getRightSubValue(), SubstitutionsCache); 256*81ad6265SDimitry Andric Result = &getOrCreateConjunction(LeftSub, RightSub); 257*81ad6265SDimitry Andric break; 258*81ad6265SDimitry Andric } 259*81ad6265SDimitry Andric default: 260*81ad6265SDimitry Andric llvm_unreachable("Unhandled Value Kind"); 261*81ad6265SDimitry Andric } 262*81ad6265SDimitry Andric SubstitutionsCache[&Val] = Result; 263*81ad6265SDimitry Andric return *Result; 264*81ad6265SDimitry Andric } 265*81ad6265SDimitry Andric 266*81ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowCondition( 267*81ad6265SDimitry Andric AtomicBoolValue &Token, 268*81ad6265SDimitry Andric llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions) { 269*81ad6265SDimitry Andric assert( 270*81ad6265SDimitry Andric Substitutions.find(&getBoolLiteralValue(true)) == Substitutions.end() && 271*81ad6265SDimitry Andric Substitutions.find(&getBoolLiteralValue(false)) == Substitutions.end() && 272*81ad6265SDimitry Andric "Do not substitute true/false boolean literals"); 273*81ad6265SDimitry Andric llvm::DenseMap<BoolValue *, BoolValue *> SubstitutionsCache( 274*81ad6265SDimitry Andric Substitutions.begin(), Substitutions.end()); 275*81ad6265SDimitry Andric return buildAndSubstituteFlowConditionWithCache(Token, SubstitutionsCache); 276*81ad6265SDimitry Andric } 277*81ad6265SDimitry Andric 278*81ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowConditionWithCache( 279*81ad6265SDimitry Andric AtomicBoolValue &Token, 280*81ad6265SDimitry Andric llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) { 281*81ad6265SDimitry Andric auto ConstraintsIT = FlowConditionConstraints.find(&Token); 282*81ad6265SDimitry Andric if (ConstraintsIT == FlowConditionConstraints.end()) { 283*81ad6265SDimitry Andric return getBoolLiteralValue(true); 284*81ad6265SDimitry Andric } 285*81ad6265SDimitry Andric auto DepsIT = FlowConditionDeps.find(&Token); 286*81ad6265SDimitry Andric if (DepsIT != FlowConditionDeps.end()) { 287*81ad6265SDimitry Andric for (AtomicBoolValue *DepToken : DepsIT->second) { 288*81ad6265SDimitry Andric auto &NewDep = buildAndSubstituteFlowConditionWithCache( 289*81ad6265SDimitry Andric *DepToken, SubstitutionsCache); 290*81ad6265SDimitry Andric SubstitutionsCache[DepToken] = &NewDep; 291*81ad6265SDimitry Andric } 292*81ad6265SDimitry Andric } 293*81ad6265SDimitry Andric return substituteBoolValue(*ConstraintsIT->second, SubstitutionsCache); 294*81ad6265SDimitry Andric } 295*81ad6265SDimitry Andric 296*81ad6265SDimitry Andric } // namespace dataflow 297*81ad6265SDimitry Andric } // namespace clang 298*81ad6265SDimitry Andric 299*81ad6265SDimitry Andric using namespace clang; 300*81ad6265SDimitry Andric 301*81ad6265SDimitry Andric const Expr &clang::dataflow::ignoreCFGOmittedNodes(const Expr &E) { 302*81ad6265SDimitry Andric const Expr *Current = &E; 303*81ad6265SDimitry Andric if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) { 304*81ad6265SDimitry Andric Current = EWC->getSubExpr(); 305*81ad6265SDimitry Andric assert(Current != nullptr); 306*81ad6265SDimitry Andric } 307*81ad6265SDimitry Andric Current = Current->IgnoreParens(); 308*81ad6265SDimitry Andric assert(Current != nullptr); 309*81ad6265SDimitry Andric return *Current; 310*81ad6265SDimitry Andric } 311*81ad6265SDimitry Andric 312*81ad6265SDimitry Andric const Stmt &clang::dataflow::ignoreCFGOmittedNodes(const Stmt &S) { 313*81ad6265SDimitry Andric if (auto *E = dyn_cast<Expr>(&S)) 314*81ad6265SDimitry Andric return ignoreCFGOmittedNodes(*E); 315*81ad6265SDimitry Andric return S; 316*81ad6265SDimitry Andric } 317*81ad6265SDimitry Andric 318*81ad6265SDimitry Andric // FIXME: Does not precisely handle non-virtual diamond inheritance. A single 319*81ad6265SDimitry Andric // field decl will be modeled for all instances of the inherited field. 320*81ad6265SDimitry Andric static void 321*81ad6265SDimitry Andric getFieldsFromClassHierarchy(QualType Type, 322*81ad6265SDimitry Andric llvm::DenseSet<const FieldDecl *> &Fields) { 323*81ad6265SDimitry Andric if (Type->isIncompleteType() || Type->isDependentType() || 324*81ad6265SDimitry Andric !Type->isRecordType()) 325*81ad6265SDimitry Andric return; 326*81ad6265SDimitry Andric 327*81ad6265SDimitry Andric for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) 328*81ad6265SDimitry Andric Fields.insert(Field); 329*81ad6265SDimitry Andric if (auto *CXXRecord = Type->getAsCXXRecordDecl()) 330*81ad6265SDimitry Andric for (const CXXBaseSpecifier &Base : CXXRecord->bases()) 331*81ad6265SDimitry Andric getFieldsFromClassHierarchy(Base.getType(), Fields); 332*81ad6265SDimitry Andric } 333*81ad6265SDimitry Andric 334*81ad6265SDimitry Andric /// Gets the set of all fields in the type. 335*81ad6265SDimitry Andric llvm::DenseSet<const FieldDecl *> 336*81ad6265SDimitry Andric clang::dataflow::getObjectFields(QualType Type) { 337*81ad6265SDimitry Andric llvm::DenseSet<const FieldDecl *> Fields; 338*81ad6265SDimitry Andric getFieldsFromClassHierarchy(Type, Fields); 339*81ad6265SDimitry Andric return Fields; 340*81ad6265SDimitry Andric } 341