181ad6265SDimitry Andric //===-- DataflowAnalysisContext.cpp -----------------------------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file defines a DataflowAnalysisContext class that owns objects that 1081ad6265SDimitry Andric // encompass the state of a program and stores context that is used during 1181ad6265SDimitry Andric // dataflow analysis. 1281ad6265SDimitry Andric // 1381ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1481ad6265SDimitry Andric 1581ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 1681ad6265SDimitry Andric #include "clang/AST/ExprCXX.h" 17*fcaf7f86SDimitry Andric #include "clang/Analysis/FlowSensitive/DebugSupport.h" 1881ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 19*fcaf7f86SDimitry Andric #include "llvm/Support/Debug.h" 2081ad6265SDimitry Andric #include <cassert> 2181ad6265SDimitry Andric #include <memory> 2281ad6265SDimitry Andric #include <utility> 2381ad6265SDimitry Andric 2481ad6265SDimitry Andric namespace clang { 2581ad6265SDimitry Andric namespace dataflow { 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric StorageLocation & 2881ad6265SDimitry Andric DataflowAnalysisContext::getStableStorageLocation(QualType Type) { 29753f127fSDimitry Andric if (!Type.isNull() && 30753f127fSDimitry Andric (Type->isStructureOrClassType() || Type->isUnionType())) { 3181ad6265SDimitry Andric // FIXME: Explore options to avoid eager initialization of fields as some of 3281ad6265SDimitry Andric // them might not be needed for a particular analysis. 3381ad6265SDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 3481ad6265SDimitry Andric for (const FieldDecl *Field : getObjectFields(Type)) 3581ad6265SDimitry Andric FieldLocs.insert({Field, &getStableStorageLocation(Field->getType())}); 3681ad6265SDimitry Andric return takeOwnership( 3781ad6265SDimitry Andric std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs))); 3881ad6265SDimitry Andric } 3981ad6265SDimitry Andric return takeOwnership(std::make_unique<ScalarStorageLocation>(Type)); 4081ad6265SDimitry Andric } 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric StorageLocation & 4381ad6265SDimitry Andric DataflowAnalysisContext::getStableStorageLocation(const VarDecl &D) { 4481ad6265SDimitry Andric if (auto *Loc = getStorageLocation(D)) 4581ad6265SDimitry Andric return *Loc; 4681ad6265SDimitry Andric auto &Loc = getStableStorageLocation(D.getType()); 4781ad6265SDimitry Andric setStorageLocation(D, Loc); 4881ad6265SDimitry Andric return Loc; 4981ad6265SDimitry Andric } 5081ad6265SDimitry Andric 5181ad6265SDimitry Andric StorageLocation & 5281ad6265SDimitry Andric DataflowAnalysisContext::getStableStorageLocation(const Expr &E) { 5381ad6265SDimitry Andric if (auto *Loc = getStorageLocation(E)) 5481ad6265SDimitry Andric return *Loc; 5581ad6265SDimitry Andric auto &Loc = getStableStorageLocation(E.getType()); 5681ad6265SDimitry Andric setStorageLocation(E, Loc); 5781ad6265SDimitry Andric return Loc; 5881ad6265SDimitry Andric } 5981ad6265SDimitry Andric 6081ad6265SDimitry Andric PointerValue & 6181ad6265SDimitry Andric DataflowAnalysisContext::getOrCreateNullPointerValue(QualType PointeeType) { 62753f127fSDimitry Andric auto CanonicalPointeeType = 63753f127fSDimitry Andric PointeeType.isNull() ? PointeeType : PointeeType.getCanonicalType(); 6481ad6265SDimitry Andric auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr); 6581ad6265SDimitry Andric if (Res.second) { 6681ad6265SDimitry Andric auto &PointeeLoc = getStableStorageLocation(CanonicalPointeeType); 6781ad6265SDimitry Andric Res.first->second = 6881ad6265SDimitry Andric &takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); 6981ad6265SDimitry Andric } 7081ad6265SDimitry Andric return *Res.first->second; 7181ad6265SDimitry Andric } 7281ad6265SDimitry Andric 7381ad6265SDimitry Andric static std::pair<BoolValue *, BoolValue *> 7481ad6265SDimitry Andric makeCanonicalBoolValuePair(BoolValue &LHS, BoolValue &RHS) { 7581ad6265SDimitry Andric auto Res = std::make_pair(&LHS, &RHS); 7681ad6265SDimitry Andric if (&RHS < &LHS) 7781ad6265SDimitry Andric std::swap(Res.first, Res.second); 7881ad6265SDimitry Andric return Res; 7981ad6265SDimitry Andric } 8081ad6265SDimitry Andric 8181ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateConjunction(BoolValue &LHS, 8281ad6265SDimitry Andric BoolValue &RHS) { 8381ad6265SDimitry Andric if (&LHS == &RHS) 8481ad6265SDimitry Andric return LHS; 8581ad6265SDimitry Andric 8681ad6265SDimitry Andric auto Res = ConjunctionVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS), 8781ad6265SDimitry Andric nullptr); 8881ad6265SDimitry Andric if (Res.second) 8981ad6265SDimitry Andric Res.first->second = 9081ad6265SDimitry Andric &takeOwnership(std::make_unique<ConjunctionValue>(LHS, RHS)); 9181ad6265SDimitry Andric return *Res.first->second; 9281ad6265SDimitry Andric } 9381ad6265SDimitry Andric 9481ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateDisjunction(BoolValue &LHS, 9581ad6265SDimitry Andric BoolValue &RHS) { 9681ad6265SDimitry Andric if (&LHS == &RHS) 9781ad6265SDimitry Andric return LHS; 9881ad6265SDimitry Andric 9981ad6265SDimitry Andric auto Res = DisjunctionVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS), 10081ad6265SDimitry Andric nullptr); 10181ad6265SDimitry Andric if (Res.second) 10281ad6265SDimitry Andric Res.first->second = 10381ad6265SDimitry Andric &takeOwnership(std::make_unique<DisjunctionValue>(LHS, RHS)); 10481ad6265SDimitry Andric return *Res.first->second; 10581ad6265SDimitry Andric } 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateNegation(BoolValue &Val) { 10881ad6265SDimitry Andric auto Res = NegationVals.try_emplace(&Val, nullptr); 10981ad6265SDimitry Andric if (Res.second) 11081ad6265SDimitry Andric Res.first->second = &takeOwnership(std::make_unique<NegationValue>(Val)); 11181ad6265SDimitry Andric return *Res.first->second; 11281ad6265SDimitry Andric } 11381ad6265SDimitry Andric 11481ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateImplication(BoolValue &LHS, 11581ad6265SDimitry Andric BoolValue &RHS) { 11681ad6265SDimitry Andric return &LHS == &RHS ? getBoolLiteralValue(true) 11781ad6265SDimitry Andric : getOrCreateDisjunction(getOrCreateNegation(LHS), RHS); 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric 12081ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::getOrCreateIff(BoolValue &LHS, 12181ad6265SDimitry Andric BoolValue &RHS) { 12281ad6265SDimitry Andric return &LHS == &RHS 12381ad6265SDimitry Andric ? getBoolLiteralValue(true) 12481ad6265SDimitry Andric : getOrCreateConjunction(getOrCreateImplication(LHS, RHS), 12581ad6265SDimitry Andric getOrCreateImplication(RHS, LHS)); 12681ad6265SDimitry Andric } 12781ad6265SDimitry Andric 12881ad6265SDimitry Andric AtomicBoolValue &DataflowAnalysisContext::makeFlowConditionToken() { 12981ad6265SDimitry Andric return createAtomicBoolValue(); 13081ad6265SDimitry Andric } 13181ad6265SDimitry Andric 13281ad6265SDimitry Andric void DataflowAnalysisContext::addFlowConditionConstraint( 13381ad6265SDimitry Andric AtomicBoolValue &Token, BoolValue &Constraint) { 13481ad6265SDimitry Andric auto Res = FlowConditionConstraints.try_emplace(&Token, &Constraint); 13581ad6265SDimitry Andric if (!Res.second) { 13681ad6265SDimitry Andric Res.first->second = &getOrCreateConjunction(*Res.first->second, Constraint); 13781ad6265SDimitry Andric } 13881ad6265SDimitry Andric } 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric AtomicBoolValue & 14181ad6265SDimitry Andric DataflowAnalysisContext::forkFlowCondition(AtomicBoolValue &Token) { 14281ad6265SDimitry Andric auto &ForkToken = makeFlowConditionToken(); 14381ad6265SDimitry Andric FlowConditionDeps[&ForkToken].insert(&Token); 14481ad6265SDimitry Andric addFlowConditionConstraint(ForkToken, Token); 14581ad6265SDimitry Andric return ForkToken; 14681ad6265SDimitry Andric } 14781ad6265SDimitry Andric 14881ad6265SDimitry Andric AtomicBoolValue & 14981ad6265SDimitry Andric DataflowAnalysisContext::joinFlowConditions(AtomicBoolValue &FirstToken, 15081ad6265SDimitry Andric AtomicBoolValue &SecondToken) { 15181ad6265SDimitry Andric auto &Token = makeFlowConditionToken(); 15281ad6265SDimitry Andric FlowConditionDeps[&Token].insert(&FirstToken); 15381ad6265SDimitry Andric FlowConditionDeps[&Token].insert(&SecondToken); 15481ad6265SDimitry Andric addFlowConditionConstraint(Token, 15581ad6265SDimitry Andric getOrCreateDisjunction(FirstToken, SecondToken)); 15681ad6265SDimitry Andric return Token; 15781ad6265SDimitry Andric } 15881ad6265SDimitry Andric 15981ad6265SDimitry Andric Solver::Result 16081ad6265SDimitry Andric DataflowAnalysisContext::querySolver(llvm::DenseSet<BoolValue *> Constraints) { 16181ad6265SDimitry Andric Constraints.insert(&getBoolLiteralValue(true)); 16281ad6265SDimitry Andric Constraints.insert(&getOrCreateNegation(getBoolLiteralValue(false))); 16381ad6265SDimitry Andric return S->solve(std::move(Constraints)); 16481ad6265SDimitry Andric } 16581ad6265SDimitry Andric 16681ad6265SDimitry Andric bool DataflowAnalysisContext::flowConditionImplies(AtomicBoolValue &Token, 16781ad6265SDimitry Andric BoolValue &Val) { 16881ad6265SDimitry Andric // Returns true if and only if truth assignment of the flow condition implies 16981ad6265SDimitry Andric // that `Val` is also true. We prove whether or not this property holds by 17081ad6265SDimitry Andric // reducing the problem to satisfiability checking. In other words, we attempt 17181ad6265SDimitry Andric // to show that assuming `Val` is false makes the constraints induced by the 17281ad6265SDimitry Andric // flow condition unsatisfiable. 17381ad6265SDimitry Andric llvm::DenseSet<BoolValue *> Constraints = {&Token, &getOrCreateNegation(Val)}; 17481ad6265SDimitry Andric llvm::DenseSet<AtomicBoolValue *> VisitedTokens; 17581ad6265SDimitry Andric addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); 17681ad6265SDimitry Andric return isUnsatisfiable(std::move(Constraints)); 17781ad6265SDimitry Andric } 17881ad6265SDimitry Andric 17981ad6265SDimitry Andric bool DataflowAnalysisContext::flowConditionIsTautology(AtomicBoolValue &Token) { 18081ad6265SDimitry Andric // Returns true if and only if we cannot prove that the flow condition can 18181ad6265SDimitry Andric // ever be false. 18281ad6265SDimitry Andric llvm::DenseSet<BoolValue *> Constraints = {&getOrCreateNegation(Token)}; 18381ad6265SDimitry Andric llvm::DenseSet<AtomicBoolValue *> VisitedTokens; 18481ad6265SDimitry Andric addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); 18581ad6265SDimitry Andric return isUnsatisfiable(std::move(Constraints)); 18681ad6265SDimitry Andric } 18781ad6265SDimitry Andric 18881ad6265SDimitry Andric bool DataflowAnalysisContext::equivalentBoolValues(BoolValue &Val1, 18981ad6265SDimitry Andric BoolValue &Val2) { 19081ad6265SDimitry Andric llvm::DenseSet<BoolValue *> Constraints = { 19181ad6265SDimitry Andric &getOrCreateNegation(getOrCreateIff(Val1, Val2))}; 19281ad6265SDimitry Andric return isUnsatisfiable(Constraints); 19381ad6265SDimitry Andric } 19481ad6265SDimitry Andric 19581ad6265SDimitry Andric void DataflowAnalysisContext::addTransitiveFlowConditionConstraints( 19681ad6265SDimitry Andric AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints, 19781ad6265SDimitry Andric llvm::DenseSet<AtomicBoolValue *> &VisitedTokens) { 19881ad6265SDimitry Andric auto Res = VisitedTokens.insert(&Token); 19981ad6265SDimitry Andric if (!Res.second) 20081ad6265SDimitry Andric return; 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric auto ConstraintsIT = FlowConditionConstraints.find(&Token); 20381ad6265SDimitry Andric if (ConstraintsIT == FlowConditionConstraints.end()) { 20481ad6265SDimitry Andric Constraints.insert(&Token); 20581ad6265SDimitry Andric } else { 20681ad6265SDimitry Andric // Bind flow condition token via `iff` to its set of constraints: 20781ad6265SDimitry Andric // FC <=> (C1 ^ C2 ^ ...), where Ci are constraints 20881ad6265SDimitry Andric Constraints.insert(&getOrCreateIff(Token, *ConstraintsIT->second)); 20981ad6265SDimitry Andric } 21081ad6265SDimitry Andric 21181ad6265SDimitry Andric auto DepsIT = FlowConditionDeps.find(&Token); 21281ad6265SDimitry Andric if (DepsIT != FlowConditionDeps.end()) { 21381ad6265SDimitry Andric for (AtomicBoolValue *DepToken : DepsIT->second) { 21481ad6265SDimitry Andric addTransitiveFlowConditionConstraints(*DepToken, Constraints, 21581ad6265SDimitry Andric VisitedTokens); 21681ad6265SDimitry Andric } 21781ad6265SDimitry Andric } 21881ad6265SDimitry Andric } 21981ad6265SDimitry Andric 22081ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::substituteBoolValue( 22181ad6265SDimitry Andric BoolValue &Val, 22281ad6265SDimitry Andric llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) { 22381ad6265SDimitry Andric auto IT = SubstitutionsCache.find(&Val); 22481ad6265SDimitry Andric if (IT != SubstitutionsCache.end()) { 22581ad6265SDimitry Andric // Return memoized result of substituting this boolean value. 22681ad6265SDimitry Andric return *IT->second; 22781ad6265SDimitry Andric } 22881ad6265SDimitry Andric 22981ad6265SDimitry Andric // Handle substitution on the boolean value (and its subvalues), saving the 23081ad6265SDimitry Andric // result into `SubstitutionsCache`. 23181ad6265SDimitry Andric BoolValue *Result; 23281ad6265SDimitry Andric switch (Val.getKind()) { 23381ad6265SDimitry Andric case Value::Kind::AtomicBool: { 23481ad6265SDimitry Andric Result = &Val; 23581ad6265SDimitry Andric break; 23681ad6265SDimitry Andric } 23781ad6265SDimitry Andric case Value::Kind::Negation: { 23881ad6265SDimitry Andric auto &Negation = *cast<NegationValue>(&Val); 23981ad6265SDimitry Andric auto &Sub = substituteBoolValue(Negation.getSubVal(), SubstitutionsCache); 24081ad6265SDimitry Andric Result = &getOrCreateNegation(Sub); 24181ad6265SDimitry Andric break; 24281ad6265SDimitry Andric } 24381ad6265SDimitry Andric case Value::Kind::Disjunction: { 24481ad6265SDimitry Andric auto &Disjunct = *cast<DisjunctionValue>(&Val); 24581ad6265SDimitry Andric auto &LeftSub = 24681ad6265SDimitry Andric substituteBoolValue(Disjunct.getLeftSubValue(), SubstitutionsCache); 24781ad6265SDimitry Andric auto &RightSub = 24881ad6265SDimitry Andric substituteBoolValue(Disjunct.getRightSubValue(), SubstitutionsCache); 24981ad6265SDimitry Andric Result = &getOrCreateDisjunction(LeftSub, RightSub); 25081ad6265SDimitry Andric break; 25181ad6265SDimitry Andric } 25281ad6265SDimitry Andric case Value::Kind::Conjunction: { 25381ad6265SDimitry Andric auto &Conjunct = *cast<ConjunctionValue>(&Val); 25481ad6265SDimitry Andric auto &LeftSub = 25581ad6265SDimitry Andric substituteBoolValue(Conjunct.getLeftSubValue(), SubstitutionsCache); 25681ad6265SDimitry Andric auto &RightSub = 25781ad6265SDimitry Andric substituteBoolValue(Conjunct.getRightSubValue(), SubstitutionsCache); 25881ad6265SDimitry Andric Result = &getOrCreateConjunction(LeftSub, RightSub); 25981ad6265SDimitry Andric break; 26081ad6265SDimitry Andric } 26181ad6265SDimitry Andric default: 26281ad6265SDimitry Andric llvm_unreachable("Unhandled Value Kind"); 26381ad6265SDimitry Andric } 26481ad6265SDimitry Andric SubstitutionsCache[&Val] = Result; 26581ad6265SDimitry Andric return *Result; 26681ad6265SDimitry Andric } 26781ad6265SDimitry Andric 26881ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowCondition( 26981ad6265SDimitry Andric AtomicBoolValue &Token, 27081ad6265SDimitry Andric llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions) { 27181ad6265SDimitry Andric assert( 27281ad6265SDimitry Andric Substitutions.find(&getBoolLiteralValue(true)) == Substitutions.end() && 27381ad6265SDimitry Andric Substitutions.find(&getBoolLiteralValue(false)) == Substitutions.end() && 27481ad6265SDimitry Andric "Do not substitute true/false boolean literals"); 27581ad6265SDimitry Andric llvm::DenseMap<BoolValue *, BoolValue *> SubstitutionsCache( 27681ad6265SDimitry Andric Substitutions.begin(), Substitutions.end()); 27781ad6265SDimitry Andric return buildAndSubstituteFlowConditionWithCache(Token, SubstitutionsCache); 27881ad6265SDimitry Andric } 27981ad6265SDimitry Andric 28081ad6265SDimitry Andric BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowConditionWithCache( 28181ad6265SDimitry Andric AtomicBoolValue &Token, 28281ad6265SDimitry Andric llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) { 28381ad6265SDimitry Andric auto ConstraintsIT = FlowConditionConstraints.find(&Token); 28481ad6265SDimitry Andric if (ConstraintsIT == FlowConditionConstraints.end()) { 28581ad6265SDimitry Andric return getBoolLiteralValue(true); 28681ad6265SDimitry Andric } 28781ad6265SDimitry Andric auto DepsIT = FlowConditionDeps.find(&Token); 28881ad6265SDimitry Andric if (DepsIT != FlowConditionDeps.end()) { 28981ad6265SDimitry Andric for (AtomicBoolValue *DepToken : DepsIT->second) { 29081ad6265SDimitry Andric auto &NewDep = buildAndSubstituteFlowConditionWithCache( 29181ad6265SDimitry Andric *DepToken, SubstitutionsCache); 29281ad6265SDimitry Andric SubstitutionsCache[DepToken] = &NewDep; 29381ad6265SDimitry Andric } 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric return substituteBoolValue(*ConstraintsIT->second, SubstitutionsCache); 29681ad6265SDimitry Andric } 29781ad6265SDimitry Andric 298*fcaf7f86SDimitry Andric void DataflowAnalysisContext::dumpFlowCondition(AtomicBoolValue &Token) { 299*fcaf7f86SDimitry Andric llvm::DenseSet<BoolValue *> Constraints = {&Token}; 300*fcaf7f86SDimitry Andric llvm::DenseSet<AtomicBoolValue *> VisitedTokens; 301*fcaf7f86SDimitry Andric addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); 302*fcaf7f86SDimitry Andric 303*fcaf7f86SDimitry Andric llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = { 304*fcaf7f86SDimitry Andric {&getBoolLiteralValue(false), "False"}, 305*fcaf7f86SDimitry Andric {&getBoolLiteralValue(true), "True"}}; 306*fcaf7f86SDimitry Andric llvm::dbgs() << debugString(Constraints, AtomNames); 307*fcaf7f86SDimitry Andric } 308*fcaf7f86SDimitry Andric 30981ad6265SDimitry Andric } // namespace dataflow 31081ad6265SDimitry Andric } // namespace clang 31181ad6265SDimitry Andric 31281ad6265SDimitry Andric using namespace clang; 31381ad6265SDimitry Andric 31481ad6265SDimitry Andric const Expr &clang::dataflow::ignoreCFGOmittedNodes(const Expr &E) { 31581ad6265SDimitry Andric const Expr *Current = &E; 31681ad6265SDimitry Andric if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) { 31781ad6265SDimitry Andric Current = EWC->getSubExpr(); 31881ad6265SDimitry Andric assert(Current != nullptr); 31981ad6265SDimitry Andric } 32081ad6265SDimitry Andric Current = Current->IgnoreParens(); 32181ad6265SDimitry Andric assert(Current != nullptr); 32281ad6265SDimitry Andric return *Current; 32381ad6265SDimitry Andric } 32481ad6265SDimitry Andric 32581ad6265SDimitry Andric const Stmt &clang::dataflow::ignoreCFGOmittedNodes(const Stmt &S) { 32681ad6265SDimitry Andric if (auto *E = dyn_cast<Expr>(&S)) 32781ad6265SDimitry Andric return ignoreCFGOmittedNodes(*E); 32881ad6265SDimitry Andric return S; 32981ad6265SDimitry Andric } 33081ad6265SDimitry Andric 33181ad6265SDimitry Andric // FIXME: Does not precisely handle non-virtual diamond inheritance. A single 33281ad6265SDimitry Andric // field decl will be modeled for all instances of the inherited field. 33381ad6265SDimitry Andric static void 33481ad6265SDimitry Andric getFieldsFromClassHierarchy(QualType Type, 33581ad6265SDimitry Andric llvm::DenseSet<const FieldDecl *> &Fields) { 33681ad6265SDimitry Andric if (Type->isIncompleteType() || Type->isDependentType() || 33781ad6265SDimitry Andric !Type->isRecordType()) 33881ad6265SDimitry Andric return; 33981ad6265SDimitry Andric 34081ad6265SDimitry Andric for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) 34181ad6265SDimitry Andric Fields.insert(Field); 34281ad6265SDimitry Andric if (auto *CXXRecord = Type->getAsCXXRecordDecl()) 34381ad6265SDimitry Andric for (const CXXBaseSpecifier &Base : CXXRecord->bases()) 34481ad6265SDimitry Andric getFieldsFromClassHierarchy(Base.getType(), Fields); 34581ad6265SDimitry Andric } 34681ad6265SDimitry Andric 34781ad6265SDimitry Andric /// Gets the set of all fields in the type. 34881ad6265SDimitry Andric llvm::DenseSet<const FieldDecl *> 34981ad6265SDimitry Andric clang::dataflow::getObjectFields(QualType Type) { 35081ad6265SDimitry Andric llvm::DenseSet<const FieldDecl *> Fields; 35181ad6265SDimitry Andric getFieldsFromClassHierarchy(Type, Fields); 35281ad6265SDimitry Andric return Fields; 35381ad6265SDimitry Andric } 354