123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- AnalysisDeclContext.h - Context for path sensitivity -----*- C++ -*-===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- //
- /// \file
- /// 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
- #define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H
- #include "clang/AST/DeclBase.h"
- #include "clang/Analysis/BodyFarm.h"
- #include "clang/Analysis/CFG.h"
- #include "clang/Analysis/CodeInjector.h"
- #include "clang/Basic/LLVM.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/FoldingSet.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/iterator_range.h"
- #include "llvm/Support/Allocator.h"
- #include <functional>
- #include <memory>
- namespace clang {
- class AnalysisDeclContextManager;
- class ASTContext;
- class BlockDecl;
- class BlockInvocationContext;
- class CFGReverseBlockReachabilityAnalysis;
- class CFGStmtMap;
- class ImplicitParamDecl;
- class LocationContext;
- class LocationContextManager;
- class ParentMap;
- class StackFrameContext;
- class Stmt;
- class VarDecl;
- /// The base class of a hierarchy of objects representing analyses tied
- /// to AnalysisDeclContext.
- class ManagedAnalysis {
- protected:
- ManagedAnalysis() = default;
- public:
- virtual ~ManagedAnalysis();
- // Subclasses need to implement:
- //
- // static const void *getTag();
- //
- // Which returns a fixed pointer address to distinguish classes of
- // analysis objects. They also need to implement:
- //
- // static [Derived*] create(AnalysisDeclContext &Ctx);
- //
- // which creates the analysis object given an AnalysisDeclContext.
- };
- /// AnalysisDeclContext contains the context data for the function, method
- /// or block under analysis.
- class AnalysisDeclContext {
- // Backpoint to the AnalysisManager object that created this
- // AnalysisDeclContext. This may be null.
- AnalysisDeclContextManager *ADCMgr;
- const Decl *const D;
- std::unique_ptr<CFG> cfg, completeCFG;
- std::unique_ptr<CFGStmtMap> cfgStmtMap;
- CFG::BuildOptions cfgBuildOptions;
- CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs = nullptr;
- bool builtCFG = false;
- bool builtCompleteCFG = false;
- std::unique_ptr<ParentMap> PM;
- std::unique_ptr<CFGReverseBlockReachabilityAnalysis> CFA;
- llvm::BumpPtrAllocator A;
- llvm::DenseMap<const BlockDecl *, void *> *ReferencedBlockVars = nullptr;
- void *ManagedAnalyses = nullptr;
- public:
- AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D);
- AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D,
- const CFG::BuildOptions &BuildOptions);
- ~AnalysisDeclContext();
- ASTContext &getASTContext() const { return D->getASTContext(); }
- const Decl *getDecl() const { return D; }
- AnalysisDeclContextManager *getManager() const { return ADCMgr; }
- CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; }
- const CFG::BuildOptions &getCFGBuildOptions() const {
- return cfgBuildOptions;
- }
- /// \returns Whether we are adding exception handling edges from CallExprs.
- /// If this is false, then try/catch statements and blocks reachable from them
- /// can appear to be dead in the CFG, analysis passes must cope with that.
- bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
- bool getUseUnoptimizedCFG() const {
- return !cfgBuildOptions.PruneTriviallyFalseEdges;
- }
- bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; }
- bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; }
- void registerForcedBlockExpression(const Stmt *stmt);
- const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
- /// \returns The body of the stored Decl \c D.
- Stmt *getBody() const;
- /// \copydoc AnalysisDeclContext::getBody()
- /// \param[out] IsAutosynthesized Specifies if the body is auto-generated
- /// by the BodyFarm.
- Stmt *getBody(bool &IsAutosynthesized) const;
- /// \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
- /// the scenes.
- /// \sa getBody
- bool isBodyAutosynthesized() const;
- /// \returns Whether the body of the Decl \c D is generated by the BodyFarm
- /// from a model file.
- ///
- /// \note The lookup is not free. We are going to call getBody behind
- /// the scenes.
- /// \sa getBody
- bool isBodyAutosynthesizedFromModelFile() const;
- CFG *getCFG();
- CFGStmtMap *getCFGStmtMap();
- CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis();
- /// \returns A version of the CFG without any edges pruned.
- CFG *getUnoptimizedCFG();
- void dumpCFG(bool ShowColors);
- /// \returns Whether we have built a CFG for this analysis context.
- ///
- /// \note This doesn't correspond to whether or not a valid CFG exists, it
- /// corresponds to whether we *attempted* to build one.
- bool isCFGBuilt() const { return builtCFG; }
- ParentMap &getParentMap();
- using referenced_decls_iterator = const VarDecl *const *;
- llvm::iterator_range<referenced_decls_iterator>
- getReferencedBlockVars(const BlockDecl *BD);
- /// \returns The ImplicitParamDecl associated with \c self if this
- /// AnalysisDeclContext wraps an ObjCMethodDecl or nullptr otherwise.
- const ImplicitParamDecl *getSelfDecl() const;
- /// \copydoc LocationContextManager::getStackFrame()
- const StackFrameContext *getStackFrame(LocationContext const *ParentLC,
- const Stmt *S, const CFGBlock *Blk,
- unsigned BlockCount, unsigned Index);
- /// \copydoc LocationContextManager::getBlockInvocationContext()
- const BlockInvocationContext *
- getBlockInvocationContext(const LocationContext *ParentLC,
- const BlockDecl *BD, const void *Data);
- /// \returns The specified analysis object, lazily running the analysis if
- /// necessary or nullptr if the analysis could not run.
- template <typename T> T *getAnalysis() {
- const void *tag = T::getTag();
- std::unique_ptr<ManagedAnalysis> &data = getAnalysisImpl(tag);
- if (!data)
- data = T::create(*this);
- return static_cast<T *>(data.get());
- }
- /// \returns Whether the root namespace of \p D is the \c std C++ namespace.
- static bool isInStdNamespace(const Decl *D);
- static std::string getFunctionName(const Decl *D);
- private:
- std::unique_ptr<ManagedAnalysis> &getAnalysisImpl(const void *tag);
- 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 {
- public:
- enum ContextKind { StackFrame, Block };
- private:
- ContextKind Kind;
- // AnalysisDeclContext can't be const since some methods may modify its
- // member.
- AnalysisDeclContext *Ctx;
- const LocationContext *Parent;
- int64_t ID;
- protected:
- LocationContext(ContextKind k, AnalysisDeclContext *ctx,
- const LocationContext *parent, int64_t ID)
- : Kind(k), Ctx(ctx), Parent(parent), ID(ID) {
- assert(ctx);
- }
- public:
- virtual ~LocationContext();
- ContextKind getKind() const { return Kind; }
- int64_t getID() const { return ID; }
- LLVM_ATTRIBUTE_RETURNS_NONNULL
- AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; }
- /// It might return null.
- const LocationContext *getParent() const { return Parent; }
- bool isParentOf(const LocationContext *LC) const;
- const Decl *getDecl() const { return Ctx->getDecl(); }
- CFG *getCFG() const { return Ctx->getCFG(); }
- template <typename T> T *getAnalysis() const { return Ctx->getAnalysis<T>(); }
- const ParentMap &getParentMap() const { return Ctx->getParentMap(); }
- /// \copydoc AnalysisDeclContext::getSelfDecl()
- const ImplicitParamDecl *getSelfDecl() const { return Ctx->getSelfDecl(); }
- const StackFrameContext *getStackFrame() const;
- /// \returns Whether the current LocationContext has no caller context.
- virtual bool inTopFrame() const;
- virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
- /// Prints out the call stack.
- ///
- /// \param Out The out stream.
- 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(
- raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0,
- bool IsDot = false,
- std::function<void(const LocationContext *)> printMoreInfoPerContext =
- [](const LocationContext *) {}) const;
- LLVM_DUMP_METHOD void dump() const;
- static void ProfileCommon(llvm::FoldingSetNodeID &ID, ContextKind ck,
- AnalysisDeclContext *ctx,
- const LocationContext *parent, const void *data);
- };
- /// It represents a stack frame of the call stack (based on CallEvent).
- class StackFrameContext : public LocationContext {
- friend class LocationContextManager;
- // The call site where this stack frame is established.
- const Stmt *CallSite;
- // The parent block of the call site.
- const CFGBlock *Block;
- // The number of times the 'Block' has been visited.
- // It allows discriminating between stack frames of the same call that is
- // called multiple times in a loop.
- const unsigned BlockCount;
- // The index of the call site in the CFGBlock.
- const unsigned Index;
- StackFrameContext(AnalysisDeclContext *ADC, const LocationContext *ParentLC,
- const Stmt *S, const CFGBlock *Block, unsigned BlockCount,
- unsigned Index, int64_t ID)
- : LocationContext(StackFrame, ADC, ParentLC, ID), CallSite(S),
- Block(Block), BlockCount(BlockCount), Index(Index) {}
- public:
- ~StackFrameContext() override = default;
- const Stmt *getCallSite() const { return CallSite; }
- const CFGBlock *getCallSiteBlock() const { return Block; }
- bool inTopFrame() const override { return getParent() == nullptr; }
- unsigned getIndex() const { return Index; }
- CFGElement getCallSiteCFGElement() const { return (*Block)[Index]; }
-
- void Profile(llvm::FoldingSetNodeID &ID) override;
- static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC,
- const LocationContext *ParentLC, const Stmt *S,
- const CFGBlock *Block, unsigned BlockCount,
- unsigned Index) {
- ProfileCommon(ID, StackFrame, ADC, ParentLC, S);
- ID.AddPointer(Block);
- ID.AddInteger(BlockCount);
- ID.AddInteger(Index);
- }
- static bool classof(const LocationContext *LC) {
- return LC->getKind() == StackFrame;
- }
- };
- /// It represents a block invocation (based on BlockCall).
- class BlockInvocationContext : public LocationContext {
- friend class LocationContextManager;
- const BlockDecl *BD;
- // FIXME: Come up with a more type-safe way to model context-sensitivity.
- const void *Data;
- BlockInvocationContext(AnalysisDeclContext *ADC,
- const LocationContext *ParentLC, const BlockDecl *BD,
- const void *Data, int64_t ID)
- : LocationContext(Block, ADC, ParentLC, ID), BD(BD), Data(Data) {}
- public:
- ~BlockInvocationContext() override = default;
- const BlockDecl *getBlockDecl() const { return BD; }
- const void *getData() const { return Data; }
- void Profile(llvm::FoldingSetNodeID &ID) override;
- static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC,
- const LocationContext *ParentLC, const BlockDecl *BD,
- const void *Data) {
- ProfileCommon(ID, Block, ADC, ParentLC, BD);
- ID.AddPointer(Data);
- }
- static bool classof(const LocationContext *LC) {
- return LC->getKind() == Block;
- }
- };
- class LocationContextManager {
- llvm::FoldingSet<LocationContext> Contexts;
- // ID used for generating a new location context.
- int64_t NewID = 0;
- public:
- ~LocationContextManager();
- /// Obtain a context of the call stack using its parent context.
- ///
- /// \param ADC The AnalysisDeclContext.
- /// \param ParentLC The parent context of this newly created context.
- /// \param S The call.
- /// \param Block The basic block.
- /// \param BlockCount The current count of entering into \p Blk.
- /// \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 *
- getBlockInvocationContext(AnalysisDeclContext *ADC,
- const LocationContext *ParentLC,
- const BlockDecl *BD, const void *Data);
- /// Discard all previously created LocationContext objects.
- void clear();
- };
- class AnalysisDeclContextManager {
- using ContextMap =
- llvm::DenseMap<const Decl *, std::unique_ptr<AnalysisDeclContext>>;
- ContextMap Contexts;
- LocationContextManager LocCtxMgr;
- CFG::BuildOptions cfgBuildOptions;
- // Pointer to an interface that can provide function bodies for
- // declarations from external source.
- std::unique_ptr<CodeInjector> Injector;
- // A factory for creating and caching implementations for common
- // methods during the analysis.
- BodyFarm FunctionBodyFarm;
- // Flag to indicate whether or not bodies should be synthesized
- // for well-known functions.
- bool SynthesizeBodies;
- public:
- AnalysisDeclContextManager(
- ASTContext &ASTCtx, bool useUnoptimizedCFG = false,
- bool addImplicitDtors = false, bool addInitializers = false,
- bool addTemporaryDtors = false, bool addLifetime = false,
- bool addLoopExit = false, bool addScopes = false,
- bool synthesizeBodies = false, bool addStaticInitBranches = false,
- bool addCXXNewAllocator = true, bool addRichCXXConstructors = true,
- bool markElidedCXXConstructors = true, bool addVirtualBaseBranches = true,
- CodeInjector *injector = nullptr);
- AnalysisDeclContext *getContext(const Decl *D);
- bool getUseUnoptimizedCFG() const {
- return !cfgBuildOptions.PruneTriviallyFalseEdges;
- }
- CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; }
- /// \returns Whether faux bodies should be synthesized for known functions.
- bool synthesizeBodies() const { return SynthesizeBodies; }
- /// Obtain the beginning context of the analysis.
- ///
- /// \returns The top level stack frame for \p D.
- const StackFrameContext *getStackFrame(const Decl *D) {
- return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr, 0,
- 0);
- }
- /// \copydoc LocationContextManager::getStackFrame()
- const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC,
- const LocationContext *Parent,
- const Stmt *S, const CFGBlock *Block,
- unsigned BlockCount, unsigned Index) {
- return LocCtxMgr.getStackFrame(ADC, Parent, S, Block, BlockCount, Index);
- }
- BodyFarm &getBodyFarm();
- /// Discard all previously created AnalysisDeclContexts.
- void clear();
- private:
- friend class AnalysisDeclContext;
- LocationContextManager &getLocationContextManager() { return LocCtxMgr; }
- };
- } // namespace clang
- #endif // LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|