xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
104eeddc0SDimitry Andric //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//
204eeddc0SDimitry Andric //
304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
604eeddc0SDimitry Andric //
704eeddc0SDimitry Andric //===----------------------------------------------------------------------===//
804eeddc0SDimitry Andric //
904eeddc0SDimitry Andric //  This file defines an Environment class that is used by dataflow analyses
1004eeddc0SDimitry Andric //  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
1104eeddc0SDimitry Andric //  program at given program points.
1204eeddc0SDimitry Andric //
1304eeddc0SDimitry Andric //===----------------------------------------------------------------------===//
1404eeddc0SDimitry Andric 
1504eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
1604eeddc0SDimitry Andric #include "clang/AST/Decl.h"
1704eeddc0SDimitry Andric #include "clang/AST/DeclCXX.h"
1804eeddc0SDimitry Andric #include "clang/AST/Type.h"
1904eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
2004eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h"
2104eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h"
2204eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h"
2381ad6265SDimitry Andric #include "llvm/Support/Casting.h"
2404eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2581ad6265SDimitry Andric #include <cassert>
2604eeddc0SDimitry Andric #include <memory>
2704eeddc0SDimitry Andric #include <utility>
2804eeddc0SDimitry Andric 
2904eeddc0SDimitry Andric namespace clang {
3004eeddc0SDimitry Andric namespace dataflow {
3104eeddc0SDimitry Andric 
3281ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current
3381ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular
3481ad6265SDimitry Andric // analysis.
3581ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3;
3681ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000;
3781ad6265SDimitry Andric 
3804eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps.
3904eeddc0SDimitry Andric template <typename K, typename V>
4004eeddc0SDimitry Andric llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
4104eeddc0SDimitry Andric                                         const llvm::DenseMap<K, V> &Map2) {
4204eeddc0SDimitry Andric   llvm::DenseMap<K, V> Result;
4304eeddc0SDimitry Andric   for (auto &Entry : Map1) {
4404eeddc0SDimitry Andric     auto It = Map2.find(Entry.first);
4504eeddc0SDimitry Andric     if (It != Map2.end() && Entry.second == It->second)
4604eeddc0SDimitry Andric       Result.insert({Entry.first, Entry.second});
4704eeddc0SDimitry Andric   }
4804eeddc0SDimitry Andric   return Result;
4904eeddc0SDimitry Andric }
5004eeddc0SDimitry Andric 
5181ad6265SDimitry Andric static bool areEquivalentIndirectionValues(Value *Val1, Value *Val2) {
5281ad6265SDimitry Andric   if (auto *IndVal1 = dyn_cast<ReferenceValue>(Val1)) {
5381ad6265SDimitry Andric     auto *IndVal2 = cast<ReferenceValue>(Val2);
5481ad6265SDimitry Andric     return &IndVal1->getReferentLoc() == &IndVal2->getReferentLoc();
5581ad6265SDimitry Andric   }
5681ad6265SDimitry Andric   if (auto *IndVal1 = dyn_cast<PointerValue>(Val1)) {
5781ad6265SDimitry Andric     auto *IndVal2 = cast<PointerValue>(Val2);
581fd87a68SDimitry Andric     return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc();
591fd87a68SDimitry Andric   }
6081ad6265SDimitry Andric   return false;
6181ad6265SDimitry Andric }
621fd87a68SDimitry Andric 
6381ad6265SDimitry Andric /// Returns true if and only if `Val1` is equivalent to `Val2`.
6481ad6265SDimitry Andric static bool equivalentValues(QualType Type, Value *Val1,
6581ad6265SDimitry Andric                              const Environment &Env1, Value *Val2,
6681ad6265SDimitry Andric                              const Environment &Env2,
6781ad6265SDimitry Andric                              Environment::ValueModel &Model) {
6881ad6265SDimitry Andric   return Val1 == Val2 || areEquivalentIndirectionValues(Val1, Val2) ||
6981ad6265SDimitry Andric          Model.compareEquivalent(Type, *Val1, Env1, *Val2, Env2);
7081ad6265SDimitry Andric }
7181ad6265SDimitry Andric 
7281ad6265SDimitry Andric /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
7381ad6265SDimitry Andric /// respectively, of the same type `Type`. Merging generally produces a single
7481ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual
7581ad6265SDimitry Andric /// meaning depends on `Model`.
7681ad6265SDimitry Andric static Value *mergeDistinctValues(QualType Type, Value *Val1,
7781ad6265SDimitry Andric                                   const Environment &Env1, Value *Val2,
7881ad6265SDimitry Andric                                   const Environment &Env2,
7981ad6265SDimitry Andric                                   Environment &MergedEnv,
8081ad6265SDimitry Andric                                   Environment::ValueModel &Model) {
8181ad6265SDimitry Andric   // Join distinct boolean values preserving information about the constraints
8281ad6265SDimitry Andric   // in the respective path conditions.
8381ad6265SDimitry Andric   //
8481ad6265SDimitry Andric   // FIXME: Does not work for backedges, since the two (or more) paths will not
8581ad6265SDimitry Andric   // have mutually exclusive conditions.
8681ad6265SDimitry Andric   if (auto *Expr1 = dyn_cast<BoolValue>(Val1)) {
8781ad6265SDimitry Andric     auto *Expr2 = cast<BoolValue>(Val2);
8881ad6265SDimitry Andric     auto &MergedVal = MergedEnv.makeAtomicBoolValue();
8981ad6265SDimitry Andric     MergedEnv.addToFlowCondition(MergedEnv.makeOr(
9081ad6265SDimitry Andric         MergedEnv.makeAnd(Env1.getFlowConditionToken(),
9181ad6265SDimitry Andric                           MergedEnv.makeIff(MergedVal, *Expr1)),
9281ad6265SDimitry Andric         MergedEnv.makeAnd(Env2.getFlowConditionToken(),
9381ad6265SDimitry Andric                           MergedEnv.makeIff(MergedVal, *Expr2))));
9481ad6265SDimitry Andric     return &MergedVal;
9581ad6265SDimitry Andric   }
9681ad6265SDimitry Andric 
9781ad6265SDimitry Andric   // FIXME: add unit tests that cover this statement.
9881ad6265SDimitry Andric   if (areEquivalentIndirectionValues(Val1, Val2)) {
9981ad6265SDimitry Andric     return Val1;
10081ad6265SDimitry Andric   }
10181ad6265SDimitry Andric 
10281ad6265SDimitry Andric   // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
10381ad6265SDimitry Andric   // returns false to avoid storing unneeded values in `DACtx`.
10481ad6265SDimitry Andric   if (Value *MergedVal = MergedEnv.createValue(Type))
10581ad6265SDimitry Andric     if (Model.merge(Type, *Val1, Env1, *Val2, Env2, *MergedVal, MergedEnv))
10681ad6265SDimitry Andric       return MergedVal;
10781ad6265SDimitry Andric 
10881ad6265SDimitry Andric   return nullptr;
10981ad6265SDimitry Andric }
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric /// Initializes a global storage value.
11281ad6265SDimitry Andric static void initGlobalVar(const VarDecl &D, Environment &Env) {
11381ad6265SDimitry Andric   if (!D.hasGlobalStorage() ||
11481ad6265SDimitry Andric       Env.getStorageLocation(D, SkipPast::None) != nullptr)
11581ad6265SDimitry Andric     return;
11681ad6265SDimitry Andric 
11781ad6265SDimitry Andric   auto &Loc = Env.createStorageLocation(D);
11881ad6265SDimitry Andric   Env.setStorageLocation(D, Loc);
11981ad6265SDimitry Andric   if (auto *Val = Env.createValue(D.getType()))
12081ad6265SDimitry Andric     Env.setValue(Loc, *Val);
12181ad6265SDimitry Andric }
12281ad6265SDimitry Andric 
12381ad6265SDimitry Andric /// Initializes a global storage value.
12481ad6265SDimitry Andric static void initGlobalVar(const Decl &D, Environment &Env) {
12581ad6265SDimitry Andric   if (auto *V = dyn_cast<VarDecl>(&D))
12681ad6265SDimitry Andric     initGlobalVar(*V, Env);
12781ad6265SDimitry Andric }
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric /// Initializes global storage values that are declared or referenced from
13081ad6265SDimitry Andric /// sub-statements of `S`.
13181ad6265SDimitry Andric // FIXME: Add support for resetting globals after function calls to enable
13281ad6265SDimitry Andric // the implementation of sound analyses.
13381ad6265SDimitry Andric static void initGlobalVars(const Stmt &S, Environment &Env) {
13481ad6265SDimitry Andric   for (auto *Child : S.children()) {
13581ad6265SDimitry Andric     if (Child != nullptr)
13681ad6265SDimitry Andric       initGlobalVars(*Child, Env);
13781ad6265SDimitry Andric   }
13881ad6265SDimitry Andric 
13981ad6265SDimitry Andric   if (auto *DS = dyn_cast<DeclStmt>(&S)) {
14081ad6265SDimitry Andric     if (DS->isSingleDecl()) {
14181ad6265SDimitry Andric       initGlobalVar(*DS->getSingleDecl(), Env);
14281ad6265SDimitry Andric     } else {
14381ad6265SDimitry Andric       for (auto *D : DS->getDeclGroup())
14481ad6265SDimitry Andric         initGlobalVar(*D, Env);
14581ad6265SDimitry Andric     }
14681ad6265SDimitry Andric   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
14781ad6265SDimitry Andric     initGlobalVar(*E->getDecl(), Env);
14881ad6265SDimitry Andric   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
14981ad6265SDimitry Andric     initGlobalVar(*E->getMemberDecl(), Env);
15081ad6265SDimitry Andric   }
15181ad6265SDimitry Andric }
15281ad6265SDimitry Andric 
15381ad6265SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx)
15481ad6265SDimitry Andric     : DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {}
15581ad6265SDimitry Andric 
15681ad6265SDimitry Andric Environment::Environment(const Environment &Other)
15781ad6265SDimitry Andric     : DACtx(Other.DACtx), DeclToLoc(Other.DeclToLoc),
15881ad6265SDimitry Andric       ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal),
15981ad6265SDimitry Andric       MemberLocToStruct(Other.MemberLocToStruct),
16081ad6265SDimitry Andric       FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) {
16181ad6265SDimitry Andric }
16281ad6265SDimitry Andric 
16381ad6265SDimitry Andric Environment &Environment::operator=(const Environment &Other) {
16481ad6265SDimitry Andric   Environment Copy(Other);
16581ad6265SDimitry Andric   *this = std::move(Copy);
16681ad6265SDimitry Andric   return *this;
1671fd87a68SDimitry Andric }
1681fd87a68SDimitry Andric 
16904eeddc0SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx,
17004eeddc0SDimitry Andric                          const DeclContext &DeclCtx)
17104eeddc0SDimitry Andric     : Environment(DACtx) {
17204eeddc0SDimitry Andric   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
17381ad6265SDimitry Andric     assert(FuncDecl->getBody() != nullptr);
17481ad6265SDimitry Andric     initGlobalVars(*FuncDecl->getBody(), *this);
17504eeddc0SDimitry Andric     for (const auto *ParamDecl : FuncDecl->parameters()) {
17604eeddc0SDimitry Andric       assert(ParamDecl != nullptr);
17704eeddc0SDimitry Andric       auto &ParamLoc = createStorageLocation(*ParamDecl);
17804eeddc0SDimitry Andric       setStorageLocation(*ParamDecl, ParamLoc);
17904eeddc0SDimitry Andric       if (Value *ParamVal = createValue(ParamDecl->getType()))
18004eeddc0SDimitry Andric         setValue(ParamLoc, *ParamVal);
18104eeddc0SDimitry Andric     }
18204eeddc0SDimitry Andric   }
18304eeddc0SDimitry Andric 
18404eeddc0SDimitry Andric   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
18581ad6265SDimitry Andric     auto *Parent = MethodDecl->getParent();
18681ad6265SDimitry Andric     assert(Parent != nullptr);
18781ad6265SDimitry Andric     if (Parent->isLambda())
18881ad6265SDimitry Andric       MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());
18981ad6265SDimitry Andric 
19081ad6265SDimitry Andric     if (MethodDecl && !MethodDecl->isStatic()) {
19104eeddc0SDimitry Andric       QualType ThisPointeeType = MethodDecl->getThisObjectType();
19204eeddc0SDimitry Andric       // FIXME: Add support for union types.
19304eeddc0SDimitry Andric       if (!ThisPointeeType->isUnionType()) {
19404eeddc0SDimitry Andric         auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
19504eeddc0SDimitry Andric         DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
19604eeddc0SDimitry Andric         if (Value *ThisPointeeVal = createValue(ThisPointeeType))
19704eeddc0SDimitry Andric           setValue(ThisPointeeLoc, *ThisPointeeVal);
19804eeddc0SDimitry Andric       }
19904eeddc0SDimitry Andric     }
20004eeddc0SDimitry Andric   }
20104eeddc0SDimitry Andric }
20204eeddc0SDimitry Andric 
203*972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const {
204*972a253aSDimitry Andric   Environment Env(*this);
205*972a253aSDimitry Andric 
206*972a253aSDimitry Andric   // FIXME: Currently this only works if the callee is never a method and the
207*972a253aSDimitry Andric   // same callee is never analyzed from multiple separate callsites. To
208*972a253aSDimitry Andric   // generalize this, we'll need to store a "context" field (probably a stack of
209*972a253aSDimitry Andric   // `const CallExpr *`s) in the `Environment`, and then change the
210*972a253aSDimitry Andric   // `DataflowAnalysisContext` class to hold a map from contexts to "frames",
211*972a253aSDimitry Andric   // where each frame stores its own version of what are currently the
212*972a253aSDimitry Andric   // `DeclToLoc`, `ExprToLoc`, and `ThisPointeeLoc` fields.
213*972a253aSDimitry Andric 
214*972a253aSDimitry Andric   const auto *FuncDecl = Call->getDirectCallee();
215*972a253aSDimitry Andric   assert(FuncDecl != nullptr);
216*972a253aSDimitry Andric   assert(FuncDecl->getBody() != nullptr);
217*972a253aSDimitry Andric   // FIXME: In order to allow the callee to reference globals, we probably need
218*972a253aSDimitry Andric   // to call `initGlobalVars` here in some way.
219*972a253aSDimitry Andric 
220*972a253aSDimitry Andric   auto ParamIt = FuncDecl->param_begin();
221*972a253aSDimitry Andric   auto ArgIt = Call->arg_begin();
222*972a253aSDimitry Andric   auto ArgEnd = Call->arg_end();
223*972a253aSDimitry Andric 
224*972a253aSDimitry Andric   // FIXME: Parameters don't always map to arguments 1:1; examples include
225*972a253aSDimitry Andric   // overloaded operators implemented as member functions, and parameter packs.
226*972a253aSDimitry Andric   for (; ArgIt != ArgEnd; ++ParamIt, ++ArgIt) {
227*972a253aSDimitry Andric     assert(ParamIt != FuncDecl->param_end());
228*972a253aSDimitry Andric 
229*972a253aSDimitry Andric     const VarDecl *Param = *ParamIt;
230*972a253aSDimitry Andric     const Expr *Arg = *ArgIt;
231*972a253aSDimitry Andric     auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
232*972a253aSDimitry Andric     assert(ArgLoc != nullptr);
233*972a253aSDimitry Andric     Env.setStorageLocation(*Param, *ArgLoc);
234*972a253aSDimitry Andric   }
235*972a253aSDimitry Andric 
236*972a253aSDimitry Andric   return Env;
237*972a253aSDimitry Andric }
238*972a253aSDimitry Andric 
2391fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other,
2401fd87a68SDimitry Andric                                Environment::ValueModel &Model) const {
24104eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
2421fd87a68SDimitry Andric 
2431fd87a68SDimitry Andric   if (DeclToLoc != Other.DeclToLoc)
2441fd87a68SDimitry Andric     return false;
2451fd87a68SDimitry Andric 
2461fd87a68SDimitry Andric   if (ExprToLoc != Other.ExprToLoc)
2471fd87a68SDimitry Andric     return false;
2481fd87a68SDimitry Andric 
24981ad6265SDimitry Andric   // Compare the contents for the intersection of their domains.
2501fd87a68SDimitry Andric   for (auto &Entry : LocToVal) {
2511fd87a68SDimitry Andric     const StorageLocation *Loc = Entry.first;
2521fd87a68SDimitry Andric     assert(Loc != nullptr);
2531fd87a68SDimitry Andric 
2541fd87a68SDimitry Andric     Value *Val = Entry.second;
2551fd87a68SDimitry Andric     assert(Val != nullptr);
2561fd87a68SDimitry Andric 
2571fd87a68SDimitry Andric     auto It = Other.LocToVal.find(Loc);
2581fd87a68SDimitry Andric     if (It == Other.LocToVal.end())
25981ad6265SDimitry Andric       continue;
2601fd87a68SDimitry Andric     assert(It->second != nullptr);
2611fd87a68SDimitry Andric 
26281ad6265SDimitry Andric     if (!equivalentValues(Loc->getType(), Val, *this, It->second, Other, Model))
2631fd87a68SDimitry Andric       return false;
2641fd87a68SDimitry Andric   }
2651fd87a68SDimitry Andric 
2661fd87a68SDimitry Andric   return true;
26704eeddc0SDimitry Andric }
26804eeddc0SDimitry Andric 
26904eeddc0SDimitry Andric LatticeJoinEffect Environment::join(const Environment &Other,
2701fd87a68SDimitry Andric                                     Environment::ValueModel &Model) {
27104eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
27204eeddc0SDimitry Andric 
27304eeddc0SDimitry Andric   auto Effect = LatticeJoinEffect::Unchanged;
27404eeddc0SDimitry Andric 
27581ad6265SDimitry Andric   Environment JoinedEnv(*DACtx);
27681ad6265SDimitry Andric 
27781ad6265SDimitry Andric   JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
27881ad6265SDimitry Andric   if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size())
27904eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
28004eeddc0SDimitry Andric 
28181ad6265SDimitry Andric   JoinedEnv.ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
28281ad6265SDimitry Andric   if (ExprToLoc.size() != JoinedEnv.ExprToLoc.size())
28304eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
28404eeddc0SDimitry Andric 
28581ad6265SDimitry Andric   JoinedEnv.MemberLocToStruct =
28681ad6265SDimitry Andric       intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct);
28781ad6265SDimitry Andric   if (MemberLocToStruct.size() != JoinedEnv.MemberLocToStruct.size())
28881ad6265SDimitry Andric     Effect = LatticeJoinEffect::Changed;
28981ad6265SDimitry Andric 
29081ad6265SDimitry Andric   // FIXME: set `Effect` as needed.
29181ad6265SDimitry Andric   JoinedEnv.FlowConditionToken = &DACtx->joinFlowConditions(
29281ad6265SDimitry Andric       *FlowConditionToken, *Other.FlowConditionToken);
29381ad6265SDimitry Andric 
29481ad6265SDimitry Andric   for (auto &Entry : LocToVal) {
29504eeddc0SDimitry Andric     const StorageLocation *Loc = Entry.first;
29604eeddc0SDimitry Andric     assert(Loc != nullptr);
29704eeddc0SDimitry Andric 
29804eeddc0SDimitry Andric     Value *Val = Entry.second;
29904eeddc0SDimitry Andric     assert(Val != nullptr);
30004eeddc0SDimitry Andric 
30104eeddc0SDimitry Andric     auto It = Other.LocToVal.find(Loc);
30204eeddc0SDimitry Andric     if (It == Other.LocToVal.end())
30304eeddc0SDimitry Andric       continue;
30404eeddc0SDimitry Andric     assert(It->second != nullptr);
30504eeddc0SDimitry Andric 
30681ad6265SDimitry Andric     if (Val == It->second) {
30781ad6265SDimitry Andric       JoinedEnv.LocToVal.insert({Loc, Val});
30804eeddc0SDimitry Andric       continue;
30904eeddc0SDimitry Andric     }
31004eeddc0SDimitry Andric 
31181ad6265SDimitry Andric     if (Value *MergedVal = mergeDistinctValues(
31281ad6265SDimitry Andric             Loc->getType(), Val, *this, It->second, Other, JoinedEnv, Model))
31381ad6265SDimitry Andric       JoinedEnv.LocToVal.insert({Loc, MergedVal});
31404eeddc0SDimitry Andric   }
31581ad6265SDimitry Andric   if (LocToVal.size() != JoinedEnv.LocToVal.size())
31604eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
31704eeddc0SDimitry Andric 
31881ad6265SDimitry Andric   *this = std::move(JoinedEnv);
31981ad6265SDimitry Andric 
32004eeddc0SDimitry Andric   return Effect;
32104eeddc0SDimitry Andric }
32204eeddc0SDimitry Andric 
32304eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) {
32481ad6265SDimitry Andric   return DACtx->getStableStorageLocation(Type);
32504eeddc0SDimitry Andric }
32604eeddc0SDimitry Andric 
32704eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
32804eeddc0SDimitry Andric   // Evaluated declarations are always assigned the same storage locations to
32904eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
33004eeddc0SDimitry Andric   // locations for evaluated declarations are stored in the analysis context.
33181ad6265SDimitry Andric   return DACtx->getStableStorageLocation(D);
33204eeddc0SDimitry Andric }
33304eeddc0SDimitry Andric 
33404eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) {
33504eeddc0SDimitry Andric   // Evaluated expressions are always assigned the same storage locations to
33604eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
33704eeddc0SDimitry Andric   // locations for evaluated expressions are stored in the analysis context.
33881ad6265SDimitry Andric   return DACtx->getStableStorageLocation(E);
33904eeddc0SDimitry Andric }
34004eeddc0SDimitry Andric 
34104eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
34204eeddc0SDimitry Andric   assert(DeclToLoc.find(&D) == DeclToLoc.end());
34304eeddc0SDimitry Andric   DeclToLoc[&D] = &Loc;
34404eeddc0SDimitry Andric }
34504eeddc0SDimitry Andric 
34604eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
34704eeddc0SDimitry Andric                                                  SkipPast SP) const {
34804eeddc0SDimitry Andric   auto It = DeclToLoc.find(&D);
34904eeddc0SDimitry Andric   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
35004eeddc0SDimitry Andric }
35104eeddc0SDimitry Andric 
35204eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
35381ad6265SDimitry Andric   const Expr &CanonE = ignoreCFGOmittedNodes(E);
35481ad6265SDimitry Andric   assert(ExprToLoc.find(&CanonE) == ExprToLoc.end());
35581ad6265SDimitry Andric   ExprToLoc[&CanonE] = &Loc;
35604eeddc0SDimitry Andric }
35704eeddc0SDimitry Andric 
35804eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E,
35904eeddc0SDimitry Andric                                                  SkipPast SP) const {
36081ad6265SDimitry Andric   // FIXME: Add a test with parens.
36181ad6265SDimitry Andric   auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
36204eeddc0SDimitry Andric   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
36304eeddc0SDimitry Andric }
36404eeddc0SDimitry Andric 
36504eeddc0SDimitry Andric StorageLocation *Environment::getThisPointeeStorageLocation() const {
36604eeddc0SDimitry Andric   return DACtx->getThisPointeeStorageLocation();
36704eeddc0SDimitry Andric }
36804eeddc0SDimitry Andric 
36981ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
37081ad6265SDimitry Andric   return DACtx->getOrCreateNullPointerValue(PointeeType);
37181ad6265SDimitry Andric }
37281ad6265SDimitry Andric 
37304eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) {
37404eeddc0SDimitry Andric   LocToVal[&Loc] = &Val;
37504eeddc0SDimitry Andric 
37604eeddc0SDimitry Andric   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
37704eeddc0SDimitry Andric     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
37804eeddc0SDimitry Andric 
37904eeddc0SDimitry Andric     const QualType Type = AggregateLoc.getType();
38004eeddc0SDimitry Andric     assert(Type->isStructureOrClassType());
38104eeddc0SDimitry Andric 
38281ad6265SDimitry Andric     for (const FieldDecl *Field : getObjectFields(Type)) {
38304eeddc0SDimitry Andric       assert(Field != nullptr);
38481ad6265SDimitry Andric       StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
38581ad6265SDimitry Andric       MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
38681ad6265SDimitry Andric       if (auto *FieldVal = StructVal->getChild(*Field))
38781ad6265SDimitry Andric         setValue(FieldLoc, *FieldVal);
38804eeddc0SDimitry Andric     }
38904eeddc0SDimitry Andric   }
39081ad6265SDimitry Andric 
391*972a253aSDimitry Andric   auto It = MemberLocToStruct.find(&Loc);
392*972a253aSDimitry Andric   if (It != MemberLocToStruct.end()) {
39381ad6265SDimitry Andric     // `Loc` is the location of a struct member so we need to also update the
39481ad6265SDimitry Andric     // value of the member in the corresponding `StructValue`.
39581ad6265SDimitry Andric 
396*972a253aSDimitry Andric     assert(It->second.first != nullptr);
397*972a253aSDimitry Andric     StructValue &StructVal = *It->second.first;
39881ad6265SDimitry Andric 
399*972a253aSDimitry Andric     assert(It->second.second != nullptr);
400*972a253aSDimitry Andric     const ValueDecl &Member = *It->second.second;
40181ad6265SDimitry Andric 
40281ad6265SDimitry Andric     StructVal.setChild(Member, Val);
40381ad6265SDimitry Andric   }
40404eeddc0SDimitry Andric }
40504eeddc0SDimitry Andric 
40604eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const {
40704eeddc0SDimitry Andric   auto It = LocToVal.find(&Loc);
40804eeddc0SDimitry Andric   return It == LocToVal.end() ? nullptr : It->second;
40904eeddc0SDimitry Andric }
41004eeddc0SDimitry Andric 
41104eeddc0SDimitry Andric Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
41204eeddc0SDimitry Andric   auto *Loc = getStorageLocation(D, SP);
41304eeddc0SDimitry Andric   if (Loc == nullptr)
41404eeddc0SDimitry Andric     return nullptr;
41504eeddc0SDimitry Andric   return getValue(*Loc);
41604eeddc0SDimitry Andric }
41704eeddc0SDimitry Andric 
41804eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const {
41904eeddc0SDimitry Andric   auto *Loc = getStorageLocation(E, SP);
42004eeddc0SDimitry Andric   if (Loc == nullptr)
42104eeddc0SDimitry Andric     return nullptr;
42204eeddc0SDimitry Andric   return getValue(*Loc);
42304eeddc0SDimitry Andric }
42404eeddc0SDimitry Andric 
42504eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) {
42604eeddc0SDimitry Andric   llvm::DenseSet<QualType> Visited;
42781ad6265SDimitry Andric   int CreatedValuesCount = 0;
42881ad6265SDimitry Andric   Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
42981ad6265SDimitry Andric                                                 CreatedValuesCount);
43081ad6265SDimitry Andric   if (CreatedValuesCount > MaxCompositeValueSize) {
43181ad6265SDimitry Andric     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
43281ad6265SDimitry Andric                  << '\n';
43381ad6265SDimitry Andric   }
43481ad6265SDimitry Andric   return Val;
43504eeddc0SDimitry Andric }
43604eeddc0SDimitry Andric 
43704eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential(
43881ad6265SDimitry Andric     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
43981ad6265SDimitry Andric     int &CreatedValuesCount) {
44004eeddc0SDimitry Andric   assert(!Type.isNull());
44104eeddc0SDimitry Andric 
44281ad6265SDimitry Andric   // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
44381ad6265SDimitry Andric   if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
44481ad6265SDimitry Andric       Depth > MaxCompositeValueDepth)
44581ad6265SDimitry Andric     return nullptr;
44681ad6265SDimitry Andric 
44781ad6265SDimitry Andric   if (Type->isBooleanType()) {
44881ad6265SDimitry Andric     CreatedValuesCount++;
44981ad6265SDimitry Andric     return &makeAtomicBoolValue();
45081ad6265SDimitry Andric   }
45181ad6265SDimitry Andric 
45204eeddc0SDimitry Andric   if (Type->isIntegerType()) {
45381ad6265SDimitry Andric     CreatedValuesCount++;
45404eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<IntegerValue>());
45504eeddc0SDimitry Andric   }
45604eeddc0SDimitry Andric 
45704eeddc0SDimitry Andric   if (Type->isReferenceType()) {
45881ad6265SDimitry Andric     CreatedValuesCount++;
45981ad6265SDimitry Andric     QualType PointeeType = Type->castAs<ReferenceType>()->getPointeeType();
46004eeddc0SDimitry Andric     auto &PointeeLoc = createStorageLocation(PointeeType);
46104eeddc0SDimitry Andric 
46281ad6265SDimitry Andric     if (Visited.insert(PointeeType.getCanonicalType()).second) {
46381ad6265SDimitry Andric       Value *PointeeVal = createValueUnlessSelfReferential(
46481ad6265SDimitry Andric           PointeeType, Visited, Depth, CreatedValuesCount);
46504eeddc0SDimitry Andric       Visited.erase(PointeeType.getCanonicalType());
46604eeddc0SDimitry Andric 
46704eeddc0SDimitry Andric       if (PointeeVal != nullptr)
46804eeddc0SDimitry Andric         setValue(PointeeLoc, *PointeeVal);
46904eeddc0SDimitry Andric     }
47004eeddc0SDimitry Andric 
47104eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
47204eeddc0SDimitry Andric   }
47304eeddc0SDimitry Andric 
47404eeddc0SDimitry Andric   if (Type->isPointerType()) {
47581ad6265SDimitry Andric     CreatedValuesCount++;
47681ad6265SDimitry Andric     QualType PointeeType = Type->castAs<PointerType>()->getPointeeType();
47704eeddc0SDimitry Andric     auto &PointeeLoc = createStorageLocation(PointeeType);
47804eeddc0SDimitry Andric 
47981ad6265SDimitry Andric     if (Visited.insert(PointeeType.getCanonicalType()).second) {
48081ad6265SDimitry Andric       Value *PointeeVal = createValueUnlessSelfReferential(
48181ad6265SDimitry Andric           PointeeType, Visited, Depth, CreatedValuesCount);
48204eeddc0SDimitry Andric       Visited.erase(PointeeType.getCanonicalType());
48304eeddc0SDimitry Andric 
48404eeddc0SDimitry Andric       if (PointeeVal != nullptr)
48504eeddc0SDimitry Andric         setValue(PointeeLoc, *PointeeVal);
48604eeddc0SDimitry Andric     }
48704eeddc0SDimitry Andric 
48804eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
48904eeddc0SDimitry Andric   }
49004eeddc0SDimitry Andric 
49104eeddc0SDimitry Andric   if (Type->isStructureOrClassType()) {
49281ad6265SDimitry Andric     CreatedValuesCount++;
49304eeddc0SDimitry Andric     // FIXME: Initialize only fields that are accessed in the context that is
49404eeddc0SDimitry Andric     // being analyzed.
49504eeddc0SDimitry Andric     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
49681ad6265SDimitry Andric     for (const FieldDecl *Field : getObjectFields(Type)) {
49704eeddc0SDimitry Andric       assert(Field != nullptr);
49804eeddc0SDimitry Andric 
49904eeddc0SDimitry Andric       QualType FieldType = Field->getType();
50004eeddc0SDimitry Andric       if (Visited.contains(FieldType.getCanonicalType()))
50104eeddc0SDimitry Andric         continue;
50204eeddc0SDimitry Andric 
50304eeddc0SDimitry Andric       Visited.insert(FieldType.getCanonicalType());
50481ad6265SDimitry Andric       if (auto *FieldValue = createValueUnlessSelfReferential(
50581ad6265SDimitry Andric               FieldType, Visited, Depth + 1, CreatedValuesCount))
50681ad6265SDimitry Andric         FieldValues.insert({Field, FieldValue});
50704eeddc0SDimitry Andric       Visited.erase(FieldType.getCanonicalType());
50804eeddc0SDimitry Andric     }
50904eeddc0SDimitry Andric 
51004eeddc0SDimitry Andric     return &takeOwnership(
51104eeddc0SDimitry Andric         std::make_unique<StructValue>(std::move(FieldValues)));
51204eeddc0SDimitry Andric   }
51304eeddc0SDimitry Andric 
51404eeddc0SDimitry Andric   return nullptr;
51504eeddc0SDimitry Andric }
51604eeddc0SDimitry Andric 
51704eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
51804eeddc0SDimitry Andric   switch (SP) {
51904eeddc0SDimitry Andric   case SkipPast::None:
52004eeddc0SDimitry Andric     return Loc;
52104eeddc0SDimitry Andric   case SkipPast::Reference:
52204eeddc0SDimitry Andric     // References cannot be chained so we only need to skip past one level of
52304eeddc0SDimitry Andric     // indirection.
52404eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
52581ad6265SDimitry Andric       return Val->getReferentLoc();
52604eeddc0SDimitry Andric     return Loc;
52704eeddc0SDimitry Andric   case SkipPast::ReferenceThenPointer:
52804eeddc0SDimitry Andric     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
52904eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
53004eeddc0SDimitry Andric       return Val->getPointeeLoc();
53104eeddc0SDimitry Andric     return LocPastRef;
53204eeddc0SDimitry Andric   }
53304eeddc0SDimitry Andric   llvm_unreachable("bad SkipPast kind");
53404eeddc0SDimitry Andric }
53504eeddc0SDimitry Andric 
53604eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc,
53704eeddc0SDimitry Andric                                          SkipPast SP) const {
53804eeddc0SDimitry Andric   return skip(*const_cast<StorageLocation *>(&Loc), SP);
53904eeddc0SDimitry Andric }
54004eeddc0SDimitry Andric 
54181ad6265SDimitry Andric void Environment::addToFlowCondition(BoolValue &Val) {
54281ad6265SDimitry Andric   DACtx->addFlowConditionConstraint(*FlowConditionToken, Val);
54381ad6265SDimitry Andric }
54481ad6265SDimitry Andric 
54581ad6265SDimitry Andric bool Environment::flowConditionImplies(BoolValue &Val) const {
54681ad6265SDimitry Andric   return DACtx->flowConditionImplies(*FlowConditionToken, Val);
54781ad6265SDimitry Andric }
54881ad6265SDimitry Andric 
549fcaf7f86SDimitry Andric void Environment::dump() const {
550fcaf7f86SDimitry Andric   DACtx->dumpFlowCondition(*FlowConditionToken);
551fcaf7f86SDimitry Andric }
552fcaf7f86SDimitry Andric 
55304eeddc0SDimitry Andric } // namespace dataflow
55404eeddc0SDimitry Andric } // namespace clang
555