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