diff options
Diffstat (limited to 'clang/lib/Analysis/AnalysisDeclContext.cpp')
| -rw-r--r-- | clang/lib/Analysis/AnalysisDeclContext.cpp | 700 | 
1 files changed, 700 insertions, 0 deletions
| diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp new file mode 100644 index 000000000000..9f58b5079c76 --- /dev/null +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -0,0 +1,700 @@ +//===- AnalysisDeclContext.cpp - Analysis context for Path Sens analysis --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines AnalysisDeclContext, a class that manages the analysis +// context data for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/AnalysisDeclContext.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/LambdaCapture.h" +#include "clang/AST/ParentMap.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" +#include "clang/Analysis/BodyFarm.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/CFGStmtMap.h" +#include "clang/Analysis/Support/BumpVector.h" +#include "clang/Basic/JsonSupport.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <memory> + +using namespace clang; + +using ManagedAnalysisMap = llvm::DenseMap<const void *, ManagedAnalysis *>; + +AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, +                                         const Decl *d, +                                         const CFG::BuildOptions &buildOptions) +    : Manager(Mgr), D(d), cfgBuildOptions(buildOptions) { +  cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; +} + +AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, +                                         const Decl *d) +    : Manager(Mgr), D(d) { +  cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; +} + +AnalysisDeclContextManager::AnalysisDeclContextManager( +    ASTContext &ASTCtx, bool useUnoptimizedCFG, bool addImplicitDtors, +    bool addInitializers, bool addTemporaryDtors, bool addLifetime, +    bool addLoopExit, bool addScopes, bool synthesizeBodies, +    bool addStaticInitBranch, bool addCXXNewAllocator, +    bool addRichCXXConstructors, bool markElidedCXXConstructors, +    bool addVirtualBaseBranches, CodeInjector *injector) +    : Injector(injector), FunctionBodyFarm(ASTCtx, injector), +      SynthesizeBodies(synthesizeBodies) { +  cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; +  cfgBuildOptions.AddImplicitDtors = addImplicitDtors; +  cfgBuildOptions.AddInitializers = addInitializers; +  cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors; +  cfgBuildOptions.AddLifetime = addLifetime; +  cfgBuildOptions.AddLoopExit = addLoopExit; +  cfgBuildOptions.AddScopes = addScopes; +  cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch; +  cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator; +  cfgBuildOptions.AddRichCXXConstructors = addRichCXXConstructors; +  cfgBuildOptions.MarkElidedCXXConstructors = markElidedCXXConstructors; +  cfgBuildOptions.AddVirtualBaseBranches = addVirtualBaseBranches; +} + +void AnalysisDeclContextManager::clear() { Contexts.clear(); } + +Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { +  IsAutosynthesized = false; +  if (const auto *FD = dyn_cast<FunctionDecl>(D)) { +    Stmt *Body = FD->getBody(); +    if (auto *CoroBody = dyn_cast_or_null<CoroutineBodyStmt>(Body)) +      Body = CoroBody->getBody(); +    if (Manager && Manager->synthesizeBodies()) { +      Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(FD); +      if (SynthesizedBody) { +        Body = SynthesizedBody; +        IsAutosynthesized = true; +      } +    } +    return Body; +  } +  else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { +    Stmt *Body = MD->getBody(); +    if (Manager && Manager->synthesizeBodies()) { +      Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(MD); +      if (SynthesizedBody) { +        Body = SynthesizedBody; +        IsAutosynthesized = true; +      } +    } +    return Body; +  } else if (const auto *BD = dyn_cast<BlockDecl>(D)) +    return BD->getBody(); +  else if (const auto *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D)) +    return FunTmpl->getTemplatedDecl()->getBody(); + +  llvm_unreachable("unknown code decl"); +} + +Stmt *AnalysisDeclContext::getBody() const { +  bool Tmp; +  return getBody(Tmp); +} + +bool AnalysisDeclContext::isBodyAutosynthesized() const { +  bool Tmp; +  getBody(Tmp); +  return Tmp; +} + +bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const { +  bool Tmp; +  Stmt *Body = getBody(Tmp); +  return Tmp && Body->getBeginLoc().isValid(); +} + +/// Returns true if \param VD is an Objective-C implicit 'self' parameter. +static bool isSelfDecl(const VarDecl *VD) { +  return isa<ImplicitParamDecl>(VD) && VD->getName() == "self"; +} + +const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const { +  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) +    return MD->getSelfDecl(); +  if (const auto *BD = dyn_cast<BlockDecl>(D)) { +    // See if 'self' was captured by the block. +    for (const auto &I : BD->captures()) { +      const VarDecl *VD = I.getVariable(); +      if (isSelfDecl(VD)) +        return dyn_cast<ImplicitParamDecl>(VD); +    } +  } + +  auto *CXXMethod = dyn_cast<CXXMethodDecl>(D); +  if (!CXXMethod) +    return nullptr; + +  const CXXRecordDecl *parent = CXXMethod->getParent(); +  if (!parent->isLambda()) +    return nullptr; + +  for (const auto &LC : parent->captures()) { +    if (!LC.capturesVariable()) +      continue; + +    VarDecl *VD = LC.getCapturedVar(); +    if (isSelfDecl(VD)) +      return dyn_cast<ImplicitParamDecl>(VD); +  } + +  return nullptr; +} + +void AnalysisDeclContext::registerForcedBlockExpression(const Stmt *stmt) { +  if (!forcedBlkExprs) +    forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs(); +  // Default construct an entry for 'stmt'. +  if (const auto *e = dyn_cast<Expr>(stmt)) +    stmt = e->IgnoreParens(); +  (void) (*forcedBlkExprs)[stmt]; +} + +const CFGBlock * +AnalysisDeclContext::getBlockForRegisteredExpression(const Stmt *stmt) { +  assert(forcedBlkExprs); +  if (const auto *e = dyn_cast<Expr>(stmt)) +    stmt = e->IgnoreParens(); +  CFG::BuildOptions::ForcedBlkExprs::const_iterator itr = +    forcedBlkExprs->find(stmt); +  assert(itr != forcedBlkExprs->end()); +  return itr->second; +} + +/// Add each synthetic statement in the CFG to the parent map, using the +/// source statement's parent. +static void addParentsForSyntheticStmts(const CFG *TheCFG, ParentMap &PM) { +  if (!TheCFG) +    return; + +  for (CFG::synthetic_stmt_iterator I = TheCFG->synthetic_stmt_begin(), +                                    E = TheCFG->synthetic_stmt_end(); +       I != E; ++I) { +    PM.setParent(I->first, PM.getParent(I->second)); +  } +} + +CFG *AnalysisDeclContext::getCFG() { +  if (!cfgBuildOptions.PruneTriviallyFalseEdges) +    return getUnoptimizedCFG(); + +  if (!builtCFG) { +    cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), cfgBuildOptions); +    // Even when the cfg is not successfully built, we don't +    // want to try building it again. +    builtCFG = true; + +    if (PM) +      addParentsForSyntheticStmts(cfg.get(), *PM); + +    // The Observer should only observe one build of the CFG. +    getCFGBuildOptions().Observer = nullptr; +  } +  return cfg.get(); +} + +CFG *AnalysisDeclContext::getUnoptimizedCFG() { +  if (!builtCompleteCFG) { +    SaveAndRestore<bool> NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges, +                                  false); +    completeCFG = +        CFG::buildCFG(D, getBody(), &D->getASTContext(), cfgBuildOptions); +    // Even when the cfg is not successfully built, we don't +    // want to try building it again. +    builtCompleteCFG = true; + +    if (PM) +      addParentsForSyntheticStmts(completeCFG.get(), *PM); + +    // The Observer should only observe one build of the CFG. +    getCFGBuildOptions().Observer = nullptr; +  } +  return completeCFG.get(); +} + +CFGStmtMap *AnalysisDeclContext::getCFGStmtMap() { +  if (cfgStmtMap) +    return cfgStmtMap.get(); + +  if (CFG *c = getCFG()) { +    cfgStmtMap.reset(CFGStmtMap::Build(c, &getParentMap())); +    return cfgStmtMap.get(); +  } + +  return nullptr; +} + +CFGReverseBlockReachabilityAnalysis *AnalysisDeclContext::getCFGReachablityAnalysis() { +  if (CFA) +    return CFA.get(); + +  if (CFG *c = getCFG()) { +    CFA.reset(new CFGReverseBlockReachabilityAnalysis(*c)); +    return CFA.get(); +  } + +  return nullptr; +} + +void AnalysisDeclContext::dumpCFG(bool ShowColors) { +  getCFG()->dump(getASTContext().getLangOpts(), ShowColors); +} + +ParentMap &AnalysisDeclContext::getParentMap() { +  if (!PM) { +    PM.reset(new ParentMap(getBody())); +    if (const auto *C = dyn_cast<CXXConstructorDecl>(getDecl())) { +      for (const auto *I : C->inits()) { +        PM->addStmt(I->getInit()); +      } +    } +    if (builtCFG) +      addParentsForSyntheticStmts(getCFG(), *PM); +    if (builtCompleteCFG) +      addParentsForSyntheticStmts(getUnoptimizedCFG(), *PM); +  } +  return *PM; +} + +AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { +  if (const auto *FD = dyn_cast<FunctionDecl>(D)) { +    // Calling 'hasBody' replaces 'FD' in place with the FunctionDecl +    // that has the body. +    FD->hasBody(FD); +    D = FD; +  } + +  std::unique_ptr<AnalysisDeclContext> &AC = Contexts[D]; +  if (!AC) +    AC = std::make_unique<AnalysisDeclContext>(this, D, cfgBuildOptions); +  return AC.get(); +} + +BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; } + +const StackFrameContext * +AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S, +                                   const CFGBlock *Blk, unsigned BlockCount, +                                   unsigned Idx) { +  return getLocationContextManager().getStackFrame(this, Parent, S, Blk, +                                                   BlockCount, Idx); +} + +const BlockInvocationContext * +AnalysisDeclContext::getBlockInvocationContext(const LocationContext *parent, +                                               const BlockDecl *BD, +                                               const void *ContextData) { +  return getLocationContextManager().getBlockInvocationContext(this, parent, +                                                               BD, ContextData); +} + +bool AnalysisDeclContext::isInStdNamespace(const Decl *D) { +  const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext(); +  const auto *ND = dyn_cast<NamespaceDecl>(DC); +  if (!ND) +    return false; + +  while (const DeclContext *Parent = ND->getParent()) { +    if (!isa<NamespaceDecl>(Parent)) +      break; +    ND = cast<NamespaceDecl>(Parent); +  } + +  return ND->isStdNamespace(); +} + +LocationContextManager &AnalysisDeclContext::getLocationContextManager() { +  assert(Manager && +         "Cannot create LocationContexts without an AnalysisDeclContextManager!"); +  return Manager->getLocationContextManager(); +} + +//===----------------------------------------------------------------------===// +// FoldingSet profiling. +//===----------------------------------------------------------------------===// + +void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID, +                                    ContextKind ck, +                                    AnalysisDeclContext *ctx, +                                    const LocationContext *parent, +                                    const void *data) { +  ID.AddInteger(ck); +  ID.AddPointer(ctx); +  ID.AddPointer(parent); +  ID.AddPointer(data); +} + +void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) { +  Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block, +          BlockCount, Index); +} + +void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { +  Profile(ID, getAnalysisDeclContext(), getParent(), Enter); +} + +void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) { +  Profile(ID, getAnalysisDeclContext(), getParent(), BD, ContextData); +} + +//===----------------------------------------------------------------------===// +// LocationContext creation. +//===----------------------------------------------------------------------===// + +template <typename LOC, typename DATA> +const LOC* +LocationContextManager::getLocationContext(AnalysisDeclContext *ctx, +                                           const LocationContext *parent, +                                           const DATA *d) { +  llvm::FoldingSetNodeID ID; +  LOC::Profile(ID, ctx, parent, d); +  void *InsertPos; + +  LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); + +  if (!L) { +    L = new LOC(ctx, parent, d, ++NewID); +    Contexts.InsertNode(L, InsertPos); +  } +  return L; +} + +const StackFrameContext *LocationContextManager::getStackFrame( +    AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s, +    const CFGBlock *blk, unsigned blockCount, unsigned idx) { +  llvm::FoldingSetNodeID ID; +  StackFrameContext::Profile(ID, ctx, parent, s, blk, blockCount, idx); +  void *InsertPos; +  auto *L = +   cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); +  if (!L) { +    L = new StackFrameContext(ctx, parent, s, blk, blockCount, idx, ++NewID); +    Contexts.InsertNode(L, InsertPos); +  } +  return L; +} + +const ScopeContext * +LocationContextManager::getScope(AnalysisDeclContext *ctx, +                                 const LocationContext *parent, +                                 const Stmt *s) { +  return getLocationContext<ScopeContext, Stmt>(ctx, parent, s); +} + +const BlockInvocationContext * +LocationContextManager::getBlockInvocationContext(AnalysisDeclContext *ctx, +                                                  const LocationContext *parent, +                                                  const BlockDecl *BD, +                                                  const void *ContextData) { +  llvm::FoldingSetNodeID ID; +  BlockInvocationContext::Profile(ID, ctx, parent, BD, ContextData); +  void *InsertPos; +  auto *L = +    cast_or_null<BlockInvocationContext>(Contexts.FindNodeOrInsertPos(ID, +                                                                    InsertPos)); +  if (!L) { +    L = new BlockInvocationContext(ctx, parent, BD, ContextData, ++NewID); +    Contexts.InsertNode(L, InsertPos); +  } +  return L; +} + +//===----------------------------------------------------------------------===// +// LocationContext methods. +//===----------------------------------------------------------------------===// + +const StackFrameContext *LocationContext::getStackFrame() const { +  const LocationContext *LC = this; +  while (LC) { +    if (const auto *SFC = dyn_cast<StackFrameContext>(LC)) +      return SFC; +    LC = LC->getParent(); +  } +  return nullptr; +} + +bool LocationContext::inTopFrame() const { +  return getStackFrame()->inTopFrame(); +} + +bool LocationContext::isParentOf(const LocationContext *LC) const { +  do { +    const LocationContext *Parent = LC->getParent(); +    if (Parent == this) +      return true; +    else +      LC = Parent; +  } while (LC); + +  return false; +} + +static void printLocation(raw_ostream &Out, const SourceManager &SM, +                          SourceLocation Loc) { +  if (Loc.isFileID() && SM.isInMainFile(Loc)) +    Out << SM.getExpansionLineNumber(Loc); +  else +    Loc.print(Out, SM); +} + +void LocationContext::dumpStack(raw_ostream &Out, const char *NL, +                                std::function<void(const LocationContext *)> +                                    printMoreInfoPerContext) const { +  ASTContext &Ctx = getAnalysisDeclContext()->getASTContext(); +  PrintingPolicy PP(Ctx.getLangOpts()); +  PP.TerseOutput = 1; + +  const SourceManager &SM = +      getAnalysisDeclContext()->getASTContext().getSourceManager(); + +  unsigned Frame = 0; +  for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) { +    switch (LCtx->getKind()) { +    case StackFrame: +      Out << "\t#" << Frame << ' '; +      ++Frame; +      if (const auto *D = dyn_cast<NamedDecl>(LCtx->getDecl())) +        Out << "Calling " << D->getQualifiedNameAsString(); +      else +        Out << "Calling anonymous code"; +      if (const Stmt *S = cast<StackFrameContext>(LCtx)->getCallSite()) { +        Out << " at line "; +        printLocation(Out, SM, S->getBeginLoc()); +      } +      break; +    case Scope: +      Out << "Entering scope"; +      break; +    case Block: +      Out << "Invoking block"; +      if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) { +        Out << " defined at line "; +        printLocation(Out, SM, D->getBeginLoc()); +      } +      break; +    } +    Out << NL; + +    printMoreInfoPerContext(LCtx); +  } +} + +void LocationContext::printJson(raw_ostream &Out, const char *NL, +                                unsigned int Space, bool IsDot, +                                std::function<void(const LocationContext *)> +                                    printMoreInfoPerContext) const { +  ASTContext &Ctx = getAnalysisDeclContext()->getASTContext(); +  PrintingPolicy PP(Ctx.getLangOpts()); +  PP.TerseOutput = 1; + +  const SourceManager &SM = +      getAnalysisDeclContext()->getASTContext().getSourceManager(); + +  unsigned Frame = 0; +  for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) { +    Indent(Out, Space, IsDot) +        << "{ \"lctx_id\": " << LCtx->getID() << ", \"location_context\": \""; +    switch (LCtx->getKind()) { +    case StackFrame: +      Out << '#' << Frame << " Call\", \"calling\": \""; +      ++Frame; +      if (const auto *D = dyn_cast<NamedDecl>(LCtx->getDecl())) +        Out << D->getQualifiedNameAsString(); +      else +        Out << "anonymous code"; + +      Out << "\", \"location\": "; +      if (const Stmt *S = cast<StackFrameContext>(LCtx)->getCallSite()) { +        printSourceLocationAsJson(Out, S->getBeginLoc(), SM); +      } else { +        Out << "null"; +      } + +      Out << ", \"items\": "; +      break; +    case Scope: +      Out << "Entering scope\" "; +      break; +    case Block: +      Out << "Invoking block\" "; +      if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) { +        Out << ", \"location\": "; +        printSourceLocationAsJson(Out, D->getBeginLoc(), SM); +        Out << ' '; +      } +      break; +    } + +    printMoreInfoPerContext(LCtx); + +    Out << '}'; +    if (LCtx->getParent()) +      Out << ','; +    Out << NL; +  } +} + +LLVM_DUMP_METHOD void LocationContext::dump() const { printJson(llvm::errs()); } + +//===----------------------------------------------------------------------===// +// Lazily generated map to query the external variables referenced by a Block. +//===----------------------------------------------------------------------===// + +namespace { + +class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{ +  BumpVector<const VarDecl *> &BEVals; +  BumpVectorContext &BC; +  llvm::SmallPtrSet<const VarDecl *, 4> Visited; +  llvm::SmallPtrSet<const DeclContext *, 4> IgnoredContexts; + +public: +  FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals, +                            BumpVectorContext &bc) +      : BEVals(bevals), BC(bc) {} + +  void VisitStmt(Stmt *S) { +    for (auto *Child : S->children()) +      if (Child) +        Visit(Child); +  } + +  void VisitDeclRefExpr(DeclRefExpr *DR) { +    // Non-local variables are also directly modified. +    if (const auto *VD = dyn_cast<VarDecl>(DR->getDecl())) { +      if (!VD->hasLocalStorage()) { +        if (Visited.insert(VD).second) +          BEVals.push_back(VD, BC); +      } +    } +  } + +  void VisitBlockExpr(BlockExpr *BR) { +    // Blocks containing blocks can transitively capture more variables. +    IgnoredContexts.insert(BR->getBlockDecl()); +    Visit(BR->getBlockDecl()->getBody()); +  } + +  void VisitPseudoObjectExpr(PseudoObjectExpr *PE) { +    for (PseudoObjectExpr::semantics_iterator it = PE->semantics_begin(), +         et = PE->semantics_end(); it != et; ++it) { +      Expr *Semantic = *it; +      if (auto *OVE = dyn_cast<OpaqueValueExpr>(Semantic)) +        Semantic = OVE->getSourceExpr(); +      Visit(Semantic); +    } +  } +}; + +} // namespace + +using DeclVec = BumpVector<const VarDecl *>; + +static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD, +                                              void *&Vec, +                                              llvm::BumpPtrAllocator &A) { +  if (Vec) +    return (DeclVec*) Vec; + +  BumpVectorContext BC(A); +  DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>(); +  new (BV) DeclVec(BC, 10); + +  // Go through the capture list. +  for (const auto &CI : BD->captures()) { +    BV->push_back(CI.getVariable(), BC); +  } + +  // Find the referenced global/static variables. +  FindBlockDeclRefExprsVals F(*BV, BC); +  F.Visit(BD->getBody()); + +  Vec = BV; +  return BV; +} + +llvm::iterator_range<AnalysisDeclContext::referenced_decls_iterator> +AnalysisDeclContext::getReferencedBlockVars(const BlockDecl *BD) { +  if (!ReferencedBlockVars) +    ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>(); + +  const DeclVec *V = +      LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); +  return llvm::make_range(V->begin(), V->end()); +} + +ManagedAnalysis *&AnalysisDeclContext::getAnalysisImpl(const void *tag) { +  if (!ManagedAnalyses) +    ManagedAnalyses = new ManagedAnalysisMap(); +  ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses; +  return (*M)[tag]; +} + +//===----------------------------------------------------------------------===// +// Cleanup. +//===----------------------------------------------------------------------===// + +ManagedAnalysis::~ManagedAnalysis() = default; + +AnalysisDeclContext::~AnalysisDeclContext() { +  delete forcedBlkExprs; +  delete ReferencedBlockVars; +  // Release the managed analyses. +  if (ManagedAnalyses) { +    ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses; +    llvm::DeleteContainerSeconds(*M); +    delete M; +  } +} + +LocationContext::~LocationContext() = default; + +LocationContextManager::~LocationContextManager() { +  clear(); +} + +void LocationContextManager::clear() { +  for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(), +       E = Contexts.end(); I != E; ) { +    LocationContext *LC = &*I; +    ++I; +    delete LC; +  } +  Contexts.clear(); +} | 
