xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision fcaf7f8644a9988098ac6be2165bce3ea4786e91)
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 
2031fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other,
2041fd87a68SDimitry Andric                                Environment::ValueModel &Model) const {
20504eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
2061fd87a68SDimitry Andric 
2071fd87a68SDimitry Andric   if (DeclToLoc != Other.DeclToLoc)
2081fd87a68SDimitry Andric     return false;
2091fd87a68SDimitry Andric 
2101fd87a68SDimitry Andric   if (ExprToLoc != Other.ExprToLoc)
2111fd87a68SDimitry Andric     return false;
2121fd87a68SDimitry Andric 
21381ad6265SDimitry Andric   // Compare the contents for the intersection of their domains.
2141fd87a68SDimitry Andric   for (auto &Entry : LocToVal) {
2151fd87a68SDimitry Andric     const StorageLocation *Loc = Entry.first;
2161fd87a68SDimitry Andric     assert(Loc != nullptr);
2171fd87a68SDimitry Andric 
2181fd87a68SDimitry Andric     Value *Val = Entry.second;
2191fd87a68SDimitry Andric     assert(Val != nullptr);
2201fd87a68SDimitry Andric 
2211fd87a68SDimitry Andric     auto It = Other.LocToVal.find(Loc);
2221fd87a68SDimitry Andric     if (It == Other.LocToVal.end())
22381ad6265SDimitry Andric       continue;
2241fd87a68SDimitry Andric     assert(It->second != nullptr);
2251fd87a68SDimitry Andric 
22681ad6265SDimitry Andric     if (!equivalentValues(Loc->getType(), Val, *this, It->second, Other, Model))
2271fd87a68SDimitry Andric       return false;
2281fd87a68SDimitry Andric   }
2291fd87a68SDimitry Andric 
2301fd87a68SDimitry Andric   return true;
23104eeddc0SDimitry Andric }
23204eeddc0SDimitry Andric 
23304eeddc0SDimitry Andric LatticeJoinEffect Environment::join(const Environment &Other,
2341fd87a68SDimitry Andric                                     Environment::ValueModel &Model) {
23504eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
23604eeddc0SDimitry Andric 
23704eeddc0SDimitry Andric   auto Effect = LatticeJoinEffect::Unchanged;
23804eeddc0SDimitry Andric 
23981ad6265SDimitry Andric   Environment JoinedEnv(*DACtx);
24081ad6265SDimitry Andric 
24181ad6265SDimitry Andric   JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
24281ad6265SDimitry Andric   if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size())
24304eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
24404eeddc0SDimitry Andric 
24581ad6265SDimitry Andric   JoinedEnv.ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
24681ad6265SDimitry Andric   if (ExprToLoc.size() != JoinedEnv.ExprToLoc.size())
24704eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
24804eeddc0SDimitry Andric 
24981ad6265SDimitry Andric   JoinedEnv.MemberLocToStruct =
25081ad6265SDimitry Andric       intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct);
25181ad6265SDimitry Andric   if (MemberLocToStruct.size() != JoinedEnv.MemberLocToStruct.size())
25281ad6265SDimitry Andric     Effect = LatticeJoinEffect::Changed;
25381ad6265SDimitry Andric 
25481ad6265SDimitry Andric   // FIXME: set `Effect` as needed.
25581ad6265SDimitry Andric   JoinedEnv.FlowConditionToken = &DACtx->joinFlowConditions(
25681ad6265SDimitry Andric       *FlowConditionToken, *Other.FlowConditionToken);
25781ad6265SDimitry Andric 
25881ad6265SDimitry Andric   for (auto &Entry : LocToVal) {
25904eeddc0SDimitry Andric     const StorageLocation *Loc = Entry.first;
26004eeddc0SDimitry Andric     assert(Loc != nullptr);
26104eeddc0SDimitry Andric 
26204eeddc0SDimitry Andric     Value *Val = Entry.second;
26304eeddc0SDimitry Andric     assert(Val != nullptr);
26404eeddc0SDimitry Andric 
26504eeddc0SDimitry Andric     auto It = Other.LocToVal.find(Loc);
26604eeddc0SDimitry Andric     if (It == Other.LocToVal.end())
26704eeddc0SDimitry Andric       continue;
26804eeddc0SDimitry Andric     assert(It->second != nullptr);
26904eeddc0SDimitry Andric 
27081ad6265SDimitry Andric     if (Val == It->second) {
27181ad6265SDimitry Andric       JoinedEnv.LocToVal.insert({Loc, Val});
27204eeddc0SDimitry Andric       continue;
27304eeddc0SDimitry Andric     }
27404eeddc0SDimitry Andric 
27581ad6265SDimitry Andric     if (Value *MergedVal = mergeDistinctValues(
27681ad6265SDimitry Andric             Loc->getType(), Val, *this, It->second, Other, JoinedEnv, Model))
27781ad6265SDimitry Andric       JoinedEnv.LocToVal.insert({Loc, MergedVal});
27804eeddc0SDimitry Andric   }
27981ad6265SDimitry Andric   if (LocToVal.size() != JoinedEnv.LocToVal.size())
28004eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
28104eeddc0SDimitry Andric 
28281ad6265SDimitry Andric   *this = std::move(JoinedEnv);
28381ad6265SDimitry Andric 
28404eeddc0SDimitry Andric   return Effect;
28504eeddc0SDimitry Andric }
28604eeddc0SDimitry Andric 
28704eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) {
28881ad6265SDimitry Andric   return DACtx->getStableStorageLocation(Type);
28904eeddc0SDimitry Andric }
29004eeddc0SDimitry Andric 
29104eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
29204eeddc0SDimitry Andric   // Evaluated declarations are always assigned the same storage locations to
29304eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
29404eeddc0SDimitry Andric   // locations for evaluated declarations are stored in the analysis context.
29581ad6265SDimitry Andric   return DACtx->getStableStorageLocation(D);
29604eeddc0SDimitry Andric }
29704eeddc0SDimitry Andric 
29804eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) {
29904eeddc0SDimitry Andric   // Evaluated expressions are always assigned the same storage locations to
30004eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
30104eeddc0SDimitry Andric   // locations for evaluated expressions are stored in the analysis context.
30281ad6265SDimitry Andric   return DACtx->getStableStorageLocation(E);
30304eeddc0SDimitry Andric }
30404eeddc0SDimitry Andric 
30504eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
30604eeddc0SDimitry Andric   assert(DeclToLoc.find(&D) == DeclToLoc.end());
30704eeddc0SDimitry Andric   DeclToLoc[&D] = &Loc;
30804eeddc0SDimitry Andric }
30904eeddc0SDimitry Andric 
31004eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
31104eeddc0SDimitry Andric                                                  SkipPast SP) const {
31204eeddc0SDimitry Andric   auto It = DeclToLoc.find(&D);
31304eeddc0SDimitry Andric   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
31404eeddc0SDimitry Andric }
31504eeddc0SDimitry Andric 
31604eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
31781ad6265SDimitry Andric   const Expr &CanonE = ignoreCFGOmittedNodes(E);
31881ad6265SDimitry Andric   assert(ExprToLoc.find(&CanonE) == ExprToLoc.end());
31981ad6265SDimitry Andric   ExprToLoc[&CanonE] = &Loc;
32004eeddc0SDimitry Andric }
32104eeddc0SDimitry Andric 
32204eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E,
32304eeddc0SDimitry Andric                                                  SkipPast SP) const {
32481ad6265SDimitry Andric   // FIXME: Add a test with parens.
32581ad6265SDimitry Andric   auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
32604eeddc0SDimitry Andric   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
32704eeddc0SDimitry Andric }
32804eeddc0SDimitry Andric 
32904eeddc0SDimitry Andric StorageLocation *Environment::getThisPointeeStorageLocation() const {
33004eeddc0SDimitry Andric   return DACtx->getThisPointeeStorageLocation();
33104eeddc0SDimitry Andric }
33204eeddc0SDimitry Andric 
33381ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
33481ad6265SDimitry Andric   return DACtx->getOrCreateNullPointerValue(PointeeType);
33581ad6265SDimitry Andric }
33681ad6265SDimitry Andric 
33704eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) {
33804eeddc0SDimitry Andric   LocToVal[&Loc] = &Val;
33904eeddc0SDimitry Andric 
34004eeddc0SDimitry Andric   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
34104eeddc0SDimitry Andric     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
34204eeddc0SDimitry Andric 
34304eeddc0SDimitry Andric     const QualType Type = AggregateLoc.getType();
34404eeddc0SDimitry Andric     assert(Type->isStructureOrClassType());
34504eeddc0SDimitry Andric 
34681ad6265SDimitry Andric     for (const FieldDecl *Field : getObjectFields(Type)) {
34704eeddc0SDimitry Andric       assert(Field != nullptr);
34881ad6265SDimitry Andric       StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
34981ad6265SDimitry Andric       MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
35081ad6265SDimitry Andric       if (auto *FieldVal = StructVal->getChild(*Field))
35181ad6265SDimitry Andric         setValue(FieldLoc, *FieldVal);
35204eeddc0SDimitry Andric     }
35304eeddc0SDimitry Andric   }
35481ad6265SDimitry Andric 
35581ad6265SDimitry Andric   auto IT = MemberLocToStruct.find(&Loc);
35681ad6265SDimitry Andric   if (IT != MemberLocToStruct.end()) {
35781ad6265SDimitry Andric     // `Loc` is the location of a struct member so we need to also update the
35881ad6265SDimitry Andric     // value of the member in the corresponding `StructValue`.
35981ad6265SDimitry Andric 
36081ad6265SDimitry Andric     assert(IT->second.first != nullptr);
36181ad6265SDimitry Andric     StructValue &StructVal = *IT->second.first;
36281ad6265SDimitry Andric 
36381ad6265SDimitry Andric     assert(IT->second.second != nullptr);
36481ad6265SDimitry Andric     const ValueDecl &Member = *IT->second.second;
36581ad6265SDimitry Andric 
36681ad6265SDimitry Andric     StructVal.setChild(Member, Val);
36781ad6265SDimitry Andric   }
36804eeddc0SDimitry Andric }
36904eeddc0SDimitry Andric 
37004eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const {
37104eeddc0SDimitry Andric   auto It = LocToVal.find(&Loc);
37204eeddc0SDimitry Andric   return It == LocToVal.end() ? nullptr : It->second;
37304eeddc0SDimitry Andric }
37404eeddc0SDimitry Andric 
37504eeddc0SDimitry Andric Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
37604eeddc0SDimitry Andric   auto *Loc = getStorageLocation(D, SP);
37704eeddc0SDimitry Andric   if (Loc == nullptr)
37804eeddc0SDimitry Andric     return nullptr;
37904eeddc0SDimitry Andric   return getValue(*Loc);
38004eeddc0SDimitry Andric }
38104eeddc0SDimitry Andric 
38204eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const {
38304eeddc0SDimitry Andric   auto *Loc = getStorageLocation(E, SP);
38404eeddc0SDimitry Andric   if (Loc == nullptr)
38504eeddc0SDimitry Andric     return nullptr;
38604eeddc0SDimitry Andric   return getValue(*Loc);
38704eeddc0SDimitry Andric }
38804eeddc0SDimitry Andric 
38904eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) {
39004eeddc0SDimitry Andric   llvm::DenseSet<QualType> Visited;
39181ad6265SDimitry Andric   int CreatedValuesCount = 0;
39281ad6265SDimitry Andric   Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
39381ad6265SDimitry Andric                                                 CreatedValuesCount);
39481ad6265SDimitry Andric   if (CreatedValuesCount > MaxCompositeValueSize) {
39581ad6265SDimitry Andric     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
39681ad6265SDimitry Andric                  << '\n';
39781ad6265SDimitry Andric   }
39881ad6265SDimitry Andric   return Val;
39904eeddc0SDimitry Andric }
40004eeddc0SDimitry Andric 
40104eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential(
40281ad6265SDimitry Andric     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
40381ad6265SDimitry Andric     int &CreatedValuesCount) {
40404eeddc0SDimitry Andric   assert(!Type.isNull());
40504eeddc0SDimitry Andric 
40681ad6265SDimitry Andric   // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
40781ad6265SDimitry Andric   if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
40881ad6265SDimitry Andric       Depth > MaxCompositeValueDepth)
40981ad6265SDimitry Andric     return nullptr;
41081ad6265SDimitry Andric 
41181ad6265SDimitry Andric   if (Type->isBooleanType()) {
41281ad6265SDimitry Andric     CreatedValuesCount++;
41381ad6265SDimitry Andric     return &makeAtomicBoolValue();
41481ad6265SDimitry Andric   }
41581ad6265SDimitry Andric 
41604eeddc0SDimitry Andric   if (Type->isIntegerType()) {
41781ad6265SDimitry Andric     CreatedValuesCount++;
41804eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<IntegerValue>());
41904eeddc0SDimitry Andric   }
42004eeddc0SDimitry Andric 
42104eeddc0SDimitry Andric   if (Type->isReferenceType()) {
42281ad6265SDimitry Andric     CreatedValuesCount++;
42381ad6265SDimitry Andric     QualType PointeeType = Type->castAs<ReferenceType>()->getPointeeType();
42404eeddc0SDimitry Andric     auto &PointeeLoc = createStorageLocation(PointeeType);
42504eeddc0SDimitry Andric 
42681ad6265SDimitry Andric     if (Visited.insert(PointeeType.getCanonicalType()).second) {
42781ad6265SDimitry Andric       Value *PointeeVal = createValueUnlessSelfReferential(
42881ad6265SDimitry Andric           PointeeType, Visited, Depth, CreatedValuesCount);
42904eeddc0SDimitry Andric       Visited.erase(PointeeType.getCanonicalType());
43004eeddc0SDimitry Andric 
43104eeddc0SDimitry Andric       if (PointeeVal != nullptr)
43204eeddc0SDimitry Andric         setValue(PointeeLoc, *PointeeVal);
43304eeddc0SDimitry Andric     }
43404eeddc0SDimitry Andric 
43504eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
43604eeddc0SDimitry Andric   }
43704eeddc0SDimitry Andric 
43804eeddc0SDimitry Andric   if (Type->isPointerType()) {
43981ad6265SDimitry Andric     CreatedValuesCount++;
44081ad6265SDimitry Andric     QualType PointeeType = Type->castAs<PointerType>()->getPointeeType();
44104eeddc0SDimitry Andric     auto &PointeeLoc = createStorageLocation(PointeeType);
44204eeddc0SDimitry Andric 
44381ad6265SDimitry Andric     if (Visited.insert(PointeeType.getCanonicalType()).second) {
44481ad6265SDimitry Andric       Value *PointeeVal = createValueUnlessSelfReferential(
44581ad6265SDimitry Andric           PointeeType, Visited, Depth, CreatedValuesCount);
44604eeddc0SDimitry Andric       Visited.erase(PointeeType.getCanonicalType());
44704eeddc0SDimitry Andric 
44804eeddc0SDimitry Andric       if (PointeeVal != nullptr)
44904eeddc0SDimitry Andric         setValue(PointeeLoc, *PointeeVal);
45004eeddc0SDimitry Andric     }
45104eeddc0SDimitry Andric 
45204eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
45304eeddc0SDimitry Andric   }
45404eeddc0SDimitry Andric 
45504eeddc0SDimitry Andric   if (Type->isStructureOrClassType()) {
45681ad6265SDimitry Andric     CreatedValuesCount++;
45704eeddc0SDimitry Andric     // FIXME: Initialize only fields that are accessed in the context that is
45804eeddc0SDimitry Andric     // being analyzed.
45904eeddc0SDimitry Andric     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
46081ad6265SDimitry Andric     for (const FieldDecl *Field : getObjectFields(Type)) {
46104eeddc0SDimitry Andric       assert(Field != nullptr);
46204eeddc0SDimitry Andric 
46304eeddc0SDimitry Andric       QualType FieldType = Field->getType();
46404eeddc0SDimitry Andric       if (Visited.contains(FieldType.getCanonicalType()))
46504eeddc0SDimitry Andric         continue;
46604eeddc0SDimitry Andric 
46704eeddc0SDimitry Andric       Visited.insert(FieldType.getCanonicalType());
46881ad6265SDimitry Andric       if (auto *FieldValue = createValueUnlessSelfReferential(
46981ad6265SDimitry Andric               FieldType, Visited, Depth + 1, CreatedValuesCount))
47081ad6265SDimitry Andric         FieldValues.insert({Field, FieldValue});
47104eeddc0SDimitry Andric       Visited.erase(FieldType.getCanonicalType());
47204eeddc0SDimitry Andric     }
47304eeddc0SDimitry Andric 
47404eeddc0SDimitry Andric     return &takeOwnership(
47504eeddc0SDimitry Andric         std::make_unique<StructValue>(std::move(FieldValues)));
47604eeddc0SDimitry Andric   }
47704eeddc0SDimitry Andric 
47804eeddc0SDimitry Andric   return nullptr;
47904eeddc0SDimitry Andric }
48004eeddc0SDimitry Andric 
48104eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
48204eeddc0SDimitry Andric   switch (SP) {
48304eeddc0SDimitry Andric   case SkipPast::None:
48404eeddc0SDimitry Andric     return Loc;
48504eeddc0SDimitry Andric   case SkipPast::Reference:
48604eeddc0SDimitry Andric     // References cannot be chained so we only need to skip past one level of
48704eeddc0SDimitry Andric     // indirection.
48804eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
48981ad6265SDimitry Andric       return Val->getReferentLoc();
49004eeddc0SDimitry Andric     return Loc;
49104eeddc0SDimitry Andric   case SkipPast::ReferenceThenPointer:
49204eeddc0SDimitry Andric     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
49304eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
49404eeddc0SDimitry Andric       return Val->getPointeeLoc();
49504eeddc0SDimitry Andric     return LocPastRef;
49604eeddc0SDimitry Andric   }
49704eeddc0SDimitry Andric   llvm_unreachable("bad SkipPast kind");
49804eeddc0SDimitry Andric }
49904eeddc0SDimitry Andric 
50004eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc,
50104eeddc0SDimitry Andric                                          SkipPast SP) const {
50204eeddc0SDimitry Andric   return skip(*const_cast<StorageLocation *>(&Loc), SP);
50304eeddc0SDimitry Andric }
50404eeddc0SDimitry Andric 
50581ad6265SDimitry Andric void Environment::addToFlowCondition(BoolValue &Val) {
50681ad6265SDimitry Andric   DACtx->addFlowConditionConstraint(*FlowConditionToken, Val);
50781ad6265SDimitry Andric }
50881ad6265SDimitry Andric 
50981ad6265SDimitry Andric bool Environment::flowConditionImplies(BoolValue &Val) const {
51081ad6265SDimitry Andric   return DACtx->flowConditionImplies(*FlowConditionToken, Val);
51181ad6265SDimitry Andric }
51281ad6265SDimitry Andric 
513*fcaf7f86SDimitry Andric void Environment::dump() const {
514*fcaf7f86SDimitry Andric   DACtx->dumpFlowCondition(*FlowConditionToken);
515*fcaf7f86SDimitry Andric }
516*fcaf7f86SDimitry Andric 
51704eeddc0SDimitry Andric } // namespace dataflow
51804eeddc0SDimitry Andric } // namespace clang
519