xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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