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