Changeset View
Changeset View
Standalone View
Standalone View
clang/include/clang/Analysis/AnalysisDeclContext.h
// AnalysisDeclContext.h - Analysis context for Path Sens analysis -*- C++ -*-// | //===- AnalysisDeclContext.h - Context for path sensitivity -----*- C++ -*-===// | ||||
// | // | ||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
// | // | ||||
// This file defines AnalysisDeclContext, a class that manages the analysis | /// \file | ||||
// context data for path sensitive analysis. | /// This file defines AnalysisDeclContext, a class that manages the analysis | ||||
/// context data for context sensitive and path sensitive analysis. | |||||
/// It also defines the helper classes to model entering, leaving or inlining | |||||
/// function calls. | |||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
#ifndef LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H | #ifndef LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H | ||||
#define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H | #define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H | ||||
#include "clang/AST/DeclBase.h" | #include "clang/AST/DeclBase.h" | ||||
#include "clang/Analysis/BodyFarm.h" | #include "clang/Analysis/BodyFarm.h" | ||||
Show All 40 Lines | public: | ||||
// Which returns a fixed pointer address to distinguish classes of | // Which returns a fixed pointer address to distinguish classes of | ||||
// analysis objects. They also need to implement: | // analysis objects. They also need to implement: | ||||
// | // | ||||
// static [Derived*] create(AnalysisDeclContext &Ctx); | // static [Derived*] create(AnalysisDeclContext &Ctx); | ||||
// | // | ||||
// which creates the analysis object given an AnalysisDeclContext. | // which creates the analysis object given an AnalysisDeclContext. | ||||
}; | }; | ||||
/// AnalysisDeclContext contains the context data for the function or method | /// AnalysisDeclContext contains the context data for the function, method | ||||
/// under analysis. | /// or block under analysis. | ||||
class AnalysisDeclContext { | class AnalysisDeclContext { | ||||
/// Backpoint to the AnalysisManager object that created this | // Backpoint to the AnalysisManager object that created this | ||||
/// AnalysisDeclContext. This may be null. | // AnalysisDeclContext. This may be null. | ||||
AnalysisDeclContextManager *Manager; | AnalysisDeclContextManager *ADCMgr; | ||||
const Decl * const D; | const Decl *const D; | ||||
std::unique_ptr<CFG> cfg, completeCFG; | std::unique_ptr<CFG> cfg, completeCFG; | ||||
std::unique_ptr<CFGStmtMap> cfgStmtMap; | std::unique_ptr<CFGStmtMap> cfgStmtMap; | ||||
CFG::BuildOptions cfgBuildOptions; | CFG::BuildOptions cfgBuildOptions; | ||||
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs = nullptr; | CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs = nullptr; | ||||
bool builtCFG = false; | bool builtCFG = false; | ||||
bool builtCompleteCFG = false; | bool builtCompleteCFG = false; | ||||
std::unique_ptr<ParentMap> PM; | std::unique_ptr<ParentMap> PM; | ||||
std::unique_ptr<CFGReverseBlockReachabilityAnalysis> CFA; | std::unique_ptr<CFGReverseBlockReachabilityAnalysis> CFA; | ||||
llvm::BumpPtrAllocator A; | llvm::BumpPtrAllocator A; | ||||
llvm::DenseMap<const BlockDecl *,void *> *ReferencedBlockVars = nullptr; | llvm::DenseMap<const BlockDecl *, void *> *ReferencedBlockVars = nullptr; | ||||
void *ManagedAnalyses = nullptr; | void *ManagedAnalyses = nullptr; | ||||
public: | public: | ||||
AnalysisDeclContext(AnalysisDeclContextManager *Mgr, | AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D); | ||||
const Decl *D); | |||||
AnalysisDeclContext(AnalysisDeclContextManager *Mgr, | AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D, | ||||
const Decl *D, | |||||
const CFG::BuildOptions &BuildOptions); | const CFG::BuildOptions &BuildOptions); | ||||
~AnalysisDeclContext(); | ~AnalysisDeclContext(); | ||||
ASTContext &getASTContext() const { return D->getASTContext(); } | ASTContext &getASTContext() const { return D->getASTContext(); } | ||||
const Decl *getDecl() const { return D; } | const Decl *getDecl() const { return D; } | ||||
/// Return the AnalysisDeclContextManager (if any) that created | AnalysisDeclContextManager *getManager() const { return ADCMgr; } | ||||
/// this AnalysisDeclContext. | |||||
AnalysisDeclContextManager *getManager() const { | |||||
return Manager; | |||||
} | |||||
/// Return the build options used to construct the CFG. | CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; } | ||||
CFG::BuildOptions &getCFGBuildOptions() { | |||||
return cfgBuildOptions; | |||||
} | |||||
const CFG::BuildOptions &getCFGBuildOptions() const { | const CFG::BuildOptions &getCFGBuildOptions() const { | ||||
return cfgBuildOptions; | return cfgBuildOptions; | ||||
} | } | ||||
/// getAddEHEdges - Return true iff we are adding exceptional edges from | /// \returns Whether we are adding exception handling edges from CallExprs. | ||||
/// callExprs. If this is false, then try/catch statements and blocks | /// If this is false, then try/catch statements and blocks reachable from them | ||||
/// reachable from them can appear to be dead in the CFG, analysis passes must | /// can appear to be dead in the CFG, analysis passes must cope with that. | ||||
/// cope with that. | |||||
bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; } | bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; } | ||||
bool getUseUnoptimizedCFG() const { | bool getUseUnoptimizedCFG() const { | ||||
return !cfgBuildOptions.PruneTriviallyFalseEdges; | return !cfgBuildOptions.PruneTriviallyFalseEdges; | ||||
} | } | ||||
bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; } | bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; } | ||||
bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; } | bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; } | ||||
void registerForcedBlockExpression(const Stmt *stmt); | void registerForcedBlockExpression(const Stmt *stmt); | ||||
const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); | const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); | ||||
/// Get the body of the Declaration. | /// \returns The body of the stored Decl \c D. | ||||
Stmt *getBody() const; | Stmt *getBody() const; | ||||
/// Get the body of the Declaration. | /// \copydoc AnalysisDeclContext::getBody() | ||||
/// \param[out] IsAutosynthesized Specifies if the body is auto-generated | /// \param[out] IsAutosynthesized Specifies if the body is auto-generated | ||||
/// by the BodyFarm. | /// by the BodyFarm. | ||||
Stmt *getBody(bool &IsAutosynthesized) const; | Stmt *getBody(bool &IsAutosynthesized) const; | ||||
/// Checks if the body of the Decl is generated by the BodyFarm. | /// \returns Whether the body of the Decl \c D is generated by the BodyFarm. | ||||
/// | /// | ||||
/// Note, the lookup is not free. We are going to call getBody behind | /// \note The lookup is not free. We are going to call getBody behind | ||||
/// the scenes. | /// the scenes. | ||||
/// \sa getBody | /// \sa getBody | ||||
bool isBodyAutosynthesized() const; | bool isBodyAutosynthesized() const; | ||||
/// Checks if the body of the Decl is generated by the BodyFarm from a | /// \returns Whether the body of the Decl \c D is generated by the BodyFarm | ||||
/// model file. | /// from a model file. | ||||
/// | /// | ||||
/// Note, the lookup is not free. We are going to call getBody behind | /// \note The lookup is not free. We are going to call getBody behind | ||||
/// the scenes. | /// the scenes. | ||||
/// \sa getBody | /// \sa getBody | ||||
bool isBodyAutosynthesizedFromModelFile() const; | bool isBodyAutosynthesizedFromModelFile() const; | ||||
CFG *getCFG(); | CFG *getCFG(); | ||||
CFGStmtMap *getCFGStmtMap(); | CFGStmtMap *getCFGStmtMap(); | ||||
CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis(); | CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis(); | ||||
/// Return a version of the CFG without any edges pruned. | /// \returns A version of the CFG without any edges pruned. | ||||
CFG *getUnoptimizedCFG(); | CFG *getUnoptimizedCFG(); | ||||
void dumpCFG(bool ShowColors); | void dumpCFG(bool ShowColors); | ||||
/// Returns true if we have built a CFG for this analysis context. | /// \returns Whether we have built a CFG for this analysis context. | ||||
/// Note that this doesn't correspond to whether or not a valid CFG exists, it | /// | ||||
/// \note This doesn't correspond to whether or not a valid CFG exists, it | |||||
/// corresponds to whether we *attempted* to build one. | /// corresponds to whether we *attempted* to build one. | ||||
bool isCFGBuilt() const { return builtCFG; } | bool isCFGBuilt() const { return builtCFG; } | ||||
ParentMap &getParentMap(); | ParentMap &getParentMap(); | ||||
using referenced_decls_iterator = const VarDecl * const *; | using referenced_decls_iterator = const VarDecl *const *; | ||||
llvm::iterator_range<referenced_decls_iterator> | llvm::iterator_range<referenced_decls_iterator> | ||||
getReferencedBlockVars(const BlockDecl *BD); | getReferencedBlockVars(const BlockDecl *BD); | ||||
/// Return the ImplicitParamDecl* associated with 'self' if this | /// \returns The ImplicitParamDecl associated with \c self if this | ||||
/// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise. | /// AnalysisDeclContext wraps an ObjCMethodDecl or nullptr otherwise. | ||||
const ImplicitParamDecl *getSelfDecl() const; | const ImplicitParamDecl *getSelfDecl() const; | ||||
const StackFrameContext *getStackFrame(LocationContext const *Parent, | /// \copydoc LocationContextManager::getStackFrame() | ||||
const StackFrameContext *getStackFrame(LocationContext const *ParentLC, | |||||
const Stmt *S, const CFGBlock *Blk, | const Stmt *S, const CFGBlock *Blk, | ||||
unsigned BlockCount, unsigned Idx); | unsigned BlockCount, unsigned Index); | ||||
/// \copydoc LocationContextManager::getBlockInvocationContext() | |||||
const BlockInvocationContext * | const BlockInvocationContext * | ||||
getBlockInvocationContext(const LocationContext *parent, | getBlockInvocationContext(const LocationContext *ParentLC, | ||||
const BlockDecl *BD, | const BlockDecl *BD, const void *Data); | ||||
const void *ContextData); | |||||
/// \returns The specified analysis object, lazily running the analysis if | |||||
/// Return the specified analysis object, lazily running the analysis if | /// necessary or nullptr if the analysis could not run. | ||||
/// necessary. Return NULL if the analysis could not run. | template <typename T> T *getAnalysis() { | ||||
template <typename T> | |||||
T *getAnalysis() { | |||||
const void *tag = T::getTag(); | const void *tag = T::getTag(); | ||||
ManagedAnalysis *&data = getAnalysisImpl(tag); | ManagedAnalysis *&data = getAnalysisImpl(tag); | ||||
if (!data) { | if (!data) { | ||||
data = T::create(*this); | data = T::create(*this); | ||||
} | } | ||||
return static_cast<T *>(data); | return static_cast<T *>(data); | ||||
} | } | ||||
/// Returns true if the root namespace of the given declaration is the 'std' | /// \returns Whether the root namespace of \p D is the \c std C++ namespace. | ||||
/// C++ namespace. | |||||
static bool isInStdNamespace(const Decl *D); | static bool isInStdNamespace(const Decl *D); | ||||
private: | private: | ||||
ManagedAnalysis *&getAnalysisImpl(const void* tag); | ManagedAnalysis *&getAnalysisImpl(const void *tag); | ||||
LocationContextManager &getLocationContextManager(); | LocationContextManager &getLocationContextManager(); | ||||
}; | }; | ||||
/// It wraps the AnalysisDeclContext to represent both the call stack with | |||||
/// the help of StackFrameContext and inside the function calls the | |||||
/// BlockInvocationContext. It is needed for context sensitive analysis to | |||||
/// model entering, leaving or inlining function calls. | |||||
class LocationContext : public llvm::FoldingSetNode { | class LocationContext : public llvm::FoldingSetNode { | ||||
public: | public: | ||||
enum ContextKind { StackFrame, Scope, Block }; | enum ContextKind { StackFrame, Block }; | ||||
private: | private: | ||||
ContextKind Kind; | ContextKind Kind; | ||||
// AnalysisDeclContext can't be const since some methods may modify its | // AnalysisDeclContext can't be const since some methods may modify its | ||||
// member. | // member. | ||||
AnalysisDeclContext *Ctx; | AnalysisDeclContext *Ctx; | ||||
const LocationContext *Parent; | const LocationContext *Parent; | ||||
int64_t ID; | int64_t ID; | ||||
protected: | protected: | ||||
LocationContext(ContextKind k, AnalysisDeclContext *ctx, | LocationContext(ContextKind k, AnalysisDeclContext *ctx, | ||||
const LocationContext *parent, | const LocationContext *parent, int64_t ID) | ||||
int64_t ID) | |||||
: Kind(k), Ctx(ctx), Parent(parent), ID(ID) {} | : Kind(k), Ctx(ctx), Parent(parent), ID(ID) {} | ||||
public: | public: | ||||
virtual ~LocationContext(); | virtual ~LocationContext(); | ||||
ContextKind getKind() const { return Kind; } | ContextKind getKind() const { return Kind; } | ||||
int64_t getID() const { | int64_t getID() const { return ID; } | ||||
return ID; | |||||
} | |||||
AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } | AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } | ||||
const LocationContext *getParent() const { return Parent; } | const LocationContext *getParent() const { return Parent; } | ||||
bool isParentOf(const LocationContext *LC) const; | bool isParentOf(const LocationContext *LC) const; | ||||
const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); } | const Decl *getDecl() const { return Ctx->getDecl(); } | ||||
CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); } | CFG *getCFG() const { return Ctx->getCFG(); } | ||||
template <typename T> | template <typename T> T *getAnalysis() const { return Ctx->getAnalysis<T>(); } | ||||
T *getAnalysis() const { | |||||
return getAnalysisDeclContext()->getAnalysis<T>(); | |||||
} | |||||
const ParentMap &getParentMap() const { | const ParentMap &getParentMap() const { return Ctx->getParentMap(); } | ||||
return getAnalysisDeclContext()->getParentMap(); | |||||
} | |||||
const ImplicitParamDecl *getSelfDecl() const { | /// \copydoc AnalysisDeclContext::getSelfDecl() | ||||
return Ctx->getSelfDecl(); | const ImplicitParamDecl *getSelfDecl() const { return Ctx->getSelfDecl(); } | ||||
} | |||||
const StackFrameContext *getStackFrame() const; | const StackFrameContext *getStackFrame() const; | ||||
/// Return true if the current LocationContext has no caller context. | /// \returns Whether the current LocationContext has no caller context. | ||||
virtual bool inTopFrame() const; | virtual bool inTopFrame() const; | ||||
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; | virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; | ||||
void dumpStack( | /// Prints out the call stack. | ||||
raw_ostream &Out, const char *NL = "\n", | /// | ||||
std::function<void(const LocationContext *)> printMoreInfoPerContext = | /// \param Out The out stream. | ||||
[](const LocationContext *) {}) const; | LLVM_DUMP_METHOD void dumpStack(raw_ostream &Out) const; | ||||
/// Prints out the call stack in \c json format. | |||||
/// | |||||
/// \param Out The out stream. | |||||
/// \param NL The newline. | |||||
/// \param Space The space count for indentation. | |||||
/// \param IsDot Whether the output format is \c dot. | |||||
/// \param printMoreInfoPerContext | |||||
/// A callback to print more information for each context, for example: | |||||
/// \code | |||||
/// [&](const LocationContext *LC) { LC->dump(); } | |||||
/// \endcode | |||||
void printJson( | void printJson( | ||||
raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0, | raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0, | ||||
bool IsDot = false, | bool IsDot = false, | ||||
std::function<void(const LocationContext *)> printMoreInfoPerContext = | std::function<void(const LocationContext *)> printMoreInfoPerContext = | ||||
[](const LocationContext *) {}) const; | [](const LocationContext *) {}) const; | ||||
void dump() const; | LLVM_DUMP_METHOD void dump() const; | ||||
public: | static void ProfileCommon(llvm::FoldingSetNodeID &ID, ContextKind ck, | ||||
static void ProfileCommon(llvm::FoldingSetNodeID &ID, | |||||
ContextKind ck, | |||||
AnalysisDeclContext *ctx, | AnalysisDeclContext *ctx, | ||||
const LocationContext *parent, | const LocationContext *parent, const void *data); | ||||
const void *data); | |||||
}; | }; | ||||
/// It represents a stack frame of the call stack (based on CallEvent). | |||||
class StackFrameContext : public LocationContext { | class StackFrameContext : public LocationContext { | ||||
friend class LocationContextManager; | friend class LocationContextManager; | ||||
// The callsite where this stack frame is established. | // The call site where this stack frame is established. | ||||
const Stmt *CallSite; | const Stmt *CallSite; | ||||
// The parent block of the callsite. | // The parent block of the call site. | ||||
const CFGBlock *Block; | const CFGBlock *Block; | ||||
// The number of times the 'Block' has been visited. | // The number of times the 'Block' has been visited. | ||||
// It allows discriminating between stack frames of the same call that is | // It allows discriminating between stack frames of the same call that is | ||||
// called multiple times in a loop. | // called multiple times in a loop. | ||||
const unsigned BlockCount; | const unsigned BlockCount; | ||||
// The index of the callsite in the CFGBlock. | // The index of the call site in the CFGBlock. | ||||
const unsigned Index; | const unsigned Index; | ||||
StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent, | StackFrameContext(AnalysisDeclContext *ADC, const LocationContext *ParentLC, | ||||
const Stmt *s, const CFGBlock *blk, unsigned blockCount, | const Stmt *S, const CFGBlock *Block, unsigned BlockCount, | ||||
unsigned idx, int64_t ID) | unsigned Index, int64_t ID) | ||||
: LocationContext(StackFrame, ctx, parent, ID), CallSite(s), Block(blk), | : LocationContext(StackFrame, ADC, ParentLC, ID), CallSite(S), | ||||
BlockCount(blockCount), Index(idx) {} | Block(Block), BlockCount(BlockCount), Index(Index) {} | ||||
public: | public: | ||||
~StackFrameContext() override = default; | ~StackFrameContext() override = default; | ||||
const Stmt *getCallSite() const { return CallSite; } | const Stmt *getCallSite() const { return CallSite; } | ||||
const CFGBlock *getCallSiteBlock() const { return Block; } | const CFGBlock *getCallSiteBlock() const { return Block; } | ||||
/// Return true if the current LocationContext has no caller context. | |||||
bool inTopFrame() const override { return getParent() == nullptr; } | bool inTopFrame() const override { return getParent() == nullptr; } | ||||
unsigned getIndex() const { return Index; } | unsigned getIndex() const { return Index; } | ||||
void Profile(llvm::FoldingSetNodeID &ID) override; | void Profile(llvm::FoldingSetNodeID &ID) override; | ||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, | static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC, | ||||
const LocationContext *parent, const Stmt *s, | const LocationContext *ParentLC, const Stmt *S, | ||||
const CFGBlock *blk, unsigned blockCount, unsigned idx) { | const CFGBlock *Block, unsigned BlockCount, | ||||
ProfileCommon(ID, StackFrame, ctx, parent, s); | unsigned Index) { | ||||
ID.AddPointer(blk); | ProfileCommon(ID, StackFrame, ADC, ParentLC, S); | ||||
ID.AddInteger(blockCount); | ID.AddPointer(Block); | ||||
ID.AddInteger(idx); | ID.AddInteger(BlockCount); | ||||
} | ID.AddInteger(Index); | ||||
static bool classof(const LocationContext *Ctx) { | |||||
return Ctx->getKind() == StackFrame; | |||||
} | |||||
}; | |||||
class ScopeContext : public LocationContext { | |||||
friend class LocationContextManager; | |||||
const Stmt *Enter; | |||||
ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent, | |||||
const Stmt *s, int64_t ID) | |||||
: LocationContext(Scope, ctx, parent, ID), Enter(s) {} | |||||
public: | |||||
~ScopeContext() override = default; | |||||
void Profile(llvm::FoldingSetNodeID &ID) override; | |||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, | |||||
const LocationContext *parent, const Stmt *s) { | |||||
ProfileCommon(ID, Scope, ctx, parent, s); | |||||
} | } | ||||
static bool classof(const LocationContext *Ctx) { | static bool classof(const LocationContext *LC) { | ||||
return Ctx->getKind() == Scope; | return LC->getKind() == StackFrame; | ||||
} | } | ||||
}; | }; | ||||
/// It represents a block invocation (based on BlockCall). | |||||
class BlockInvocationContext : public LocationContext { | class BlockInvocationContext : public LocationContext { | ||||
friend class LocationContextManager; | friend class LocationContextManager; | ||||
const BlockDecl *BD; | const BlockDecl *BD; | ||||
// FIXME: Come up with a more type-safe way to model context-sensitivity. | // FIXME: Come up with a more type-safe way to model context-sensitivity. | ||||
const void *ContextData; | const void *Data; | ||||
BlockInvocationContext(AnalysisDeclContext *ctx, | BlockInvocationContext(AnalysisDeclContext *ADC, | ||||
const LocationContext *parent, const BlockDecl *bd, | const LocationContext *ParentLC, const BlockDecl *BD, | ||||
const void *contextData, int64_t ID) | const void *Data, int64_t ID) | ||||
: LocationContext(Block, ctx, parent, ID), BD(bd), | : LocationContext(Block, ADC, ParentLC, ID), BD(BD), Data(Data) {} | ||||
ContextData(contextData) {} | |||||
public: | public: | ||||
~BlockInvocationContext() override = default; | ~BlockInvocationContext() override = default; | ||||
const BlockDecl *getBlockDecl() const { return BD; } | const BlockDecl *getBlockDecl() const { return BD; } | ||||
const void *getContextData() const { return ContextData; } | const void *getData() const { return Data; } | ||||
void Profile(llvm::FoldingSetNodeID &ID) override; | void Profile(llvm::FoldingSetNodeID &ID) override; | ||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, | static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC, | ||||
const LocationContext *parent, const BlockDecl *bd, | const LocationContext *ParentLC, const BlockDecl *BD, | ||||
const void *contextData) { | const void *Data) { | ||||
ProfileCommon(ID, Block, ctx, parent, bd); | ProfileCommon(ID, Block, ADC, ParentLC, BD); | ||||
ID.AddPointer(contextData); | ID.AddPointer(Data); | ||||
} | } | ||||
static bool classof(const LocationContext *Ctx) { | static bool classof(const LocationContext *LC) { | ||||
return Ctx->getKind() == Block; | return LC->getKind() == Block; | ||||
} | } | ||||
}; | }; | ||||
class LocationContextManager { | class LocationContextManager { | ||||
llvm::FoldingSet<LocationContext> Contexts; | llvm::FoldingSet<LocationContext> Contexts; | ||||
/// ID used for generating a new location context. | // ID used for generating a new location context. | ||||
int64_t NewID = 0; | int64_t NewID = 0; | ||||
public: | public: | ||||
~LocationContextManager(); | ~LocationContextManager(); | ||||
const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx, | /// Obtain a context of the call stack using its parent context. | ||||
const LocationContext *parent, | /// | ||||
const Stmt *s, const CFGBlock *blk, | /// \param ADC The AnalysisDeclContext. | ||||
unsigned blockCount, unsigned idx); | /// \param ParentLC The parent context of this newly created context. | ||||
/// \param S The call. | |||||
const ScopeContext *getScope(AnalysisDeclContext *ctx, | /// \param Block The basic block. | ||||
const LocationContext *parent, | /// \param BlockCount The current count of entering into \p Blk. | ||||
const Stmt *s); | /// \param Index The index of \p Blk. | ||||
/// \returns The context for \p D with parent context \p ParentLC. | |||||
const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC, | |||||
const LocationContext *ParentLC, | |||||
const Stmt *S, const CFGBlock *Block, | |||||
unsigned BlockCount, unsigned Index); | |||||
/// Obtain a context of the block invocation using its parent context. | |||||
/// | |||||
/// \param ADC The AnalysisDeclContext. | |||||
/// \param ParentLC The parent context of this newly created context. | |||||
/// \param BD The BlockDecl. | |||||
/// \param Data The raw data to store as part of the context. | |||||
const BlockInvocationContext * | const BlockInvocationContext * | ||||
getBlockInvocationContext(AnalysisDeclContext *ctx, | getBlockInvocationContext(AnalysisDeclContext *ADC, | ||||
const LocationContext *parent, | const LocationContext *ParentLC, | ||||
const BlockDecl *BD, | const BlockDecl *BD, const void *Data); | ||||
const void *ContextData); | |||||
/// Discard all previously created LocationContext objects. | /// Discard all previously created LocationContext objects. | ||||
void clear(); | void clear(); | ||||
private: | |||||
template <typename LOC, typename DATA> | |||||
const LOC *getLocationContext(AnalysisDeclContext *ctx, | |||||
const LocationContext *parent, | |||||
const DATA *d); | |||||
}; | }; | ||||
class AnalysisDeclContextManager { | class AnalysisDeclContextManager { | ||||
using ContextMap = | using ContextMap = | ||||
llvm::DenseMap<const Decl *, std::unique_ptr<AnalysisDeclContext>>; | llvm::DenseMap<const Decl *, std::unique_ptr<AnalysisDeclContext>>; | ||||
ContextMap Contexts; | ContextMap Contexts; | ||||
LocationContextManager LocContexts; | LocationContextManager LocCtxMgr; | ||||
CFG::BuildOptions cfgBuildOptions; | CFG::BuildOptions cfgBuildOptions; | ||||
/// Pointer to an interface that can provide function bodies for | // Pointer to an interface that can provide function bodies for | ||||
/// declarations from external source. | // declarations from external source. | ||||
std::unique_ptr<CodeInjector> Injector; | std::unique_ptr<CodeInjector> Injector; | ||||
/// A factory for creating and caching implementations for common | // A factory for creating and caching implementations for common | ||||
/// methods during the analysis. | // methods during the analysis. | ||||
BodyFarm FunctionBodyFarm; | BodyFarm FunctionBodyFarm; | ||||
/// Flag to indicate whether or not bodies should be synthesized | // Flag to indicate whether or not bodies should be synthesized | ||||
/// for well-known functions. | // for well-known functions. | ||||
bool SynthesizeBodies; | bool SynthesizeBodies; | ||||
public: | public: | ||||
AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false, | AnalysisDeclContextManager( | ||||
bool addImplicitDtors = false, | ASTContext &ASTCtx, bool useUnoptimizedCFG = false, | ||||
bool addInitializers = false, | bool addImplicitDtors = false, bool addInitializers = false, | ||||
bool addTemporaryDtors = false, | bool addTemporaryDtors = false, bool addLifetime = false, | ||||
bool addLifetime = false, | bool addLoopExit = false, bool addScopes = false, | ||||
bool addLoopExit = false, | bool synthesizeBodies = false, bool addStaticInitBranches = false, | ||||
bool addScopes = false, | bool addCXXNewAllocator = true, bool addRichCXXConstructors = true, | ||||
bool synthesizeBodies = false, | bool markElidedCXXConstructors = true, bool addVirtualBaseBranches = true, | ||||
bool addStaticInitBranches = false, | |||||
bool addCXXNewAllocator = true, | |||||
bool addRichCXXConstructors = true, | |||||
bool markElidedCXXConstructors = true, | |||||
bool addVirtualBaseBranches = true, | |||||
CodeInjector *injector = nullptr); | CodeInjector *injector = nullptr); | ||||
AnalysisDeclContext *getContext(const Decl *D); | AnalysisDeclContext *getContext(const Decl *D); | ||||
bool getUseUnoptimizedCFG() const { | bool getUseUnoptimizedCFG() const { | ||||
return !cfgBuildOptions.PruneTriviallyFalseEdges; | return !cfgBuildOptions.PruneTriviallyFalseEdges; | ||||
} | } | ||||
CFG::BuildOptions &getCFGBuildOptions() { | CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; } | ||||
return cfgBuildOptions; | |||||
} | |||||
/// Return true if faux bodies should be synthesized for well-known | /// \returns Whether faux bodies should be synthesized for known functions. | ||||
/// functions. | |||||
bool synthesizeBodies() const { return SynthesizeBodies; } | bool synthesizeBodies() const { return SynthesizeBodies; } | ||||
const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx, | /// Obtain the beginning context of the analysis. | ||||
const LocationContext *Parent, | /// | ||||
const Stmt *S, const CFGBlock *Blk, | /// \returns The top level stack frame for \p D. | ||||
unsigned BlockCount, unsigned Idx) { | |||||
return LocContexts.getStackFrame(Ctx, Parent, S, Blk, BlockCount, Idx); | |||||
} | |||||
// Get the top level stack frame. | |||||
const StackFrameContext *getStackFrame(const Decl *D) { | const StackFrameContext *getStackFrame(const Decl *D) { | ||||
return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr, | return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr, 0, | ||||
0, 0); | 0); | ||||
} | } | ||||
// Get a stack frame with parent. | /// \copydoc LocationContextManager::getStackFrame() | ||||
StackFrameContext const *getStackFrame(const Decl *D, | const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC, | ||||
const LocationContext *Parent, | const LocationContext *Parent, | ||||
const Stmt *S, const CFGBlock *Blk, | const Stmt *S, const CFGBlock *Block, | ||||
unsigned BlockCount, unsigned Idx) { | unsigned BlockCount, unsigned Index) { | ||||
return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, BlockCount, | return LocCtxMgr.getStackFrame(ADC, Parent, S, Block, BlockCount, Index); | ||||
Idx); | |||||
} | } | ||||
/// Get a reference to {@code BodyFarm} instance. | |||||
BodyFarm &getBodyFarm(); | BodyFarm &getBodyFarm(); | ||||
/// Discard all previously created AnalysisDeclContexts. | /// Discard all previously created AnalysisDeclContexts. | ||||
void clear(); | void clear(); | ||||
private: | private: | ||||
friend class AnalysisDeclContext; | friend class AnalysisDeclContext; | ||||
LocationContextManager &getLocationContextManager() { | LocationContextManager &getLocationContextManager() { return LocCtxMgr; } | ||||
return LocContexts; | |||||
} | |||||
}; | }; | ||||
} // namespace clang | } // namespace clang | ||||
#endif // LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H | #endif // LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H |