diff options
author | dim <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
commit | 554bcb69c2d785a011a30e7db87a36a87fe7db10 (patch) | |
tree | 9abb1a658a297776086f4e0dfa6ca533de02104e /include/clang/Analysis | |
parent | bb67ca86b31f67faee50bd10c3b036d65751745a (diff) | |
download | FreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.zip FreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.tar.gz |
Vendor import of clang trunk r161861:
http://llvm.org/svn/llvm-project/cfe/trunk@161861
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r-- | include/clang/Analysis/Analyses/FormatString.h | 65 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/ThreadSafety.h | 9 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/UninitializedValues.h | 60 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisContext.h | 50 | ||||
-rw-r--r-- | include/clang/Analysis/CFG.h | 12 | ||||
-rw-r--r-- | include/clang/Analysis/CallGraph.h | 10 | ||||
-rw-r--r-- | include/clang/Analysis/ProgramPoint.h | 169 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h | 2 |
8 files changed, 264 insertions, 113 deletions
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 9ec27ce..7f50ee3 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -175,6 +175,7 @@ public: switch (kind) { case PrintErrno: assert(IsPrintf); + return false; case PercentArg: return false; default: @@ -200,7 +201,7 @@ protected: Kind kind; }; -class ArgTypeResult { +class ArgType { public: enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, AnyCharTy, CStrTy, WCStrTy, WIntTy }; @@ -208,26 +209,26 @@ private: const Kind K; QualType T; const char *Name; - ArgTypeResult(bool) : K(InvalidTy), Name(0) {} + bool Ptr; public: - ArgTypeResult(Kind k = UnknownTy) : K(k), Name(0) {} - ArgTypeResult(Kind k, const char *n) : K(k), Name(n) {} - ArgTypeResult(QualType t) : K(SpecificTy), T(t), Name(0) {} - ArgTypeResult(QualType t, const char *n) : K(SpecificTy), T(t), Name(n) {} - ArgTypeResult(CanQualType t) : K(SpecificTy), T(t), Name(0) {} - - static ArgTypeResult Invalid() { return ArgTypeResult(true); } + ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {} + ArgType(QualType t, const char *n = 0) + : K(SpecificTy), T(t), Name(n), Ptr(false) {} + ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0), Ptr(false) {} + static ArgType Invalid() { return ArgType(InvalidTy); } bool isValid() const { return K != InvalidTy; } - const QualType *getSpecificType() const { - return K == SpecificTy ? &T : 0; + /// Create an ArgType which corresponds to the type pointer to A. + static ArgType PtrTo(const ArgType& A) { + assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); + ArgType Res = A; + Res.Ptr = true; + return Res; } bool matchesType(ASTContext &C, QualType argTy) const; - bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; } - QualType getRepresentativeType(ASTContext &C) const; std::string getRepresentativeTypeName(ASTContext &C) const; @@ -278,7 +279,7 @@ public: return length + UsesDotPrefix; } - ArgTypeResult getArgType(ASTContext &Ctx) const; + ArgType getArgType(ASTContext &Ctx) const; void toString(raw_ostream &os) const; @@ -354,6 +355,10 @@ public: bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; bool hasStandardLengthConversionCombination() const; + + /// For a TypedefType QT, if it is a named integer type such as size_t, + /// assign the appropriate value to LM and return true. + static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM); }; } // end analyze_format_string namespace @@ -387,7 +392,7 @@ public: } }; -using analyze_format_string::ArgTypeResult; +using analyze_format_string::ArgType; using analyze_format_string::LengthModifier; using analyze_format_string::OptionalAmount; using analyze_format_string::OptionalFlag; @@ -462,7 +467,7 @@ public: /// will return null if the format specifier does not have /// a matching data argument or the matching argument matches /// more than one type. - ArgTypeResult getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; + ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; const OptionalFlag &hasThousandsGrouping() const { return HasThousandsGrouping; @@ -516,35 +521,11 @@ public: } }; -using analyze_format_string::ArgTypeResult; +using analyze_format_string::ArgType; using analyze_format_string::LengthModifier; using analyze_format_string::OptionalAmount; using analyze_format_string::OptionalFlag; -class ScanfArgTypeResult : public ArgTypeResult { -public: - enum Kind { UnknownTy, InvalidTy, CStrTy, WCStrTy, PtrToArgTypeResultTy }; -private: - Kind K; - ArgTypeResult A; - const char *Name; - QualType getRepresentativeType(ASTContext &C) const; -public: - ScanfArgTypeResult(Kind k = UnknownTy, const char* n = 0) : K(k), Name(n) {} - ScanfArgTypeResult(ArgTypeResult a, const char *n = 0) - : K(PtrToArgTypeResultTy), A(a), Name(n) { - assert(A.isValid()); - } - - static ScanfArgTypeResult Invalid() { return ScanfArgTypeResult(InvalidTy); } - - bool isValid() const { return K != InvalidTy; } - - bool matchesType(ASTContext& C, QualType argTy) const; - - std::string getRepresentativeTypeName(ASTContext& C) const; -}; - class ScanfSpecifier : public analyze_format_string::FormatSpecifier { OptionalFlag SuppressAssignment; // '*' public: @@ -573,7 +554,7 @@ public: return CS.consumesDataArgument() && !SuppressAssignment; } - ScanfArgTypeResult getArgType(ASTContext &Ctx) const; + ArgType getArgType(ASTContext &Ctx) const; bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx); diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h index 26e258d..742cc04 100644 --- a/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/include/clang/Analysis/Analyses/ThreadSafety.h @@ -60,7 +60,8 @@ enum AccessKind { enum LockErrorKind { LEK_LockedSomeLoopIterations, LEK_LockedSomePredecessors, - LEK_LockedAtEndOfFunction + LEK_LockedAtEndOfFunction, + LEK_NotLockedAtEndOfFunction }; /// Handler class for thread safety warnings. @@ -123,11 +124,11 @@ public: /// Warn when a protected operation occurs while the specific mutex protecting /// the operation is not locked. - /// \param LockName -- A StringRef name for the lock expression, to be printed - /// in the error message. /// \param D -- The decl for the protected variable or function /// \param POK -- The kind of protected operation (e.g. variable access) - /// \param AK -- The kind of access (i.e. read or write) that occurred + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param LK -- The kind of access (i.e. read or write) that occurred /// \param Loc -- The location of the protected operation. virtual void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK, Name LockName, diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index 4ee6698..45ce4de 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -15,6 +15,8 @@ #ifndef LLVM_CLANG_UNINIT_VALS_H #define LLVM_CLANG_UNINIT_VALS_H +#include "llvm/ADT/SmallVector.h" + namespace clang { class AnalysisDeclContext; @@ -23,15 +25,67 @@ class DeclContext; class Expr; class VarDecl; +/// A use of a variable, which might be uninitialized. +class UninitUse { +public: + struct Branch { + const Stmt *Terminator; + unsigned Output; + }; + +private: + /// The expression which uses this variable. + const Expr *User; + + /// Does this use always see an uninitialized value? + bool AlwaysUninit; + + /// This use is always uninitialized if it occurs after any of these branches + /// is taken. + llvm::SmallVector<Branch, 2> UninitBranches; + +public: + UninitUse(const Expr *User, bool AlwaysUninit) : + User(User), AlwaysUninit(AlwaysUninit) {} + + void addUninitBranch(Branch B) { + UninitBranches.push_back(B); + } + + /// Get the expression containing the uninitialized use. + const Expr *getUser() const { return User; } + + /// The kind of uninitialized use. + enum Kind { + /// The use might be uninitialized. + Maybe, + /// The use is uninitialized whenever a certain branch is taken. + Sometimes, + /// The use is always uninitialized. + Always + }; + + /// Get the kind of uninitialized use. + Kind getKind() const { + return AlwaysUninit ? Always : + !branch_empty() ? Sometimes : Maybe; + } + + typedef llvm::SmallVectorImpl<Branch>::const_iterator branch_iterator; + /// Branches which inevitably result in the variable being used uninitialized. + branch_iterator branch_begin() const { return UninitBranches.begin(); } + branch_iterator branch_end() const { return UninitBranches.end(); } + bool branch_empty() const { return UninitBranches.empty(); } +}; + class UninitVariablesHandler { public: UninitVariablesHandler() {} virtual ~UninitVariablesHandler(); /// Called when the uninitialized variable is used at the given expression. - virtual void handleUseOfUninitVariable(const Expr *ex, - const VarDecl *vd, - bool isAlwaysUninit) {} + virtual void handleUseOfUninitVariable(const VarDecl *vd, + const UninitUse &use) {} /// Called when the uninitialized variable analysis detects the /// idiom 'int x = x'. All other uses of 'x' within the initializer diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 6b6f8ef..46b4e93 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -38,6 +38,7 @@ class PseudoConstantAnalysis; class ImplicitParamDecl; class LocationContextManager; class StackFrameContext; +class BlockInvocationContext; class AnalysisDeclContextManager; class LocationContext; @@ -73,9 +74,6 @@ class AnalysisDeclContext { const Decl *D; - // TranslationUnit is NULL if we don't have multiple translation units. - idx::TranslationUnit *TU; - OwningPtr<CFG> cfg, completeCFG; OwningPtr<CFGStmtMap> cfgStmtMap; @@ -98,12 +96,10 @@ class AnalysisDeclContext { public: AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *D, - idx::TranslationUnit *TU); + const Decl *D); AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D, - idx::TranslationUnit *TU, const CFG::BuildOptions &BuildOptions); ~AnalysisDeclContext(); @@ -111,8 +107,6 @@ public: ASTContext &getASTContext() { return D->getASTContext(); } const Decl *getDecl() const { return D; } - idx::TranslationUnit *getTranslationUnit() const { return TU; } - /// Return the build options used to construct the CFG. CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; @@ -169,6 +163,11 @@ public: const Stmt *S, const CFGBlock *Blk, unsigned Idx); + + const BlockInvocationContext * + getBlockInvocationContext(const LocationContext *parent, + const BlockDecl *BD, + const void *ContextData); /// Return the specified analysis object, lazily running the analysis if /// necessary. Return NULL if the analysis could not run. @@ -212,10 +211,6 @@ public: AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } - idx::TranslationUnit *getTranslationUnit() const { - return Ctx->getTranslationUnit(); - } - const LocationContext *getParent() const { return Parent; } bool isParentOf(const LocationContext *LC) const; @@ -238,8 +233,6 @@ public: } const StackFrameContext *getCurrentStackFrame() const; - const StackFrameContext * - getStackFrameForDeclContext(const DeclContext *DC) const; virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; @@ -318,27 +311,32 @@ public: }; class BlockInvocationContext : public LocationContext { - // FIXME: Add back context-sensivity (we don't want libAnalysis to know - // about MemRegion). const BlockDecl *BD; + + // FIXME: Come up with a more type-safe way to model context-sensitivity. + const void *ContextData; friend class LocationContextManager; BlockInvocationContext(AnalysisDeclContext *ctx, const LocationContext *parent, - const BlockDecl *bd) - : LocationContext(Block, ctx, parent), BD(bd) {} + const BlockDecl *bd, const void *contextData) + : LocationContext(Block, ctx, parent), BD(bd), ContextData(contextData) {} public: ~BlockInvocationContext() {} const BlockDecl *getBlockDecl() const { return BD; } + + const void *getContextData() const { return ContextData; } void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, - const LocationContext *parent, const BlockDecl *bd) { + const LocationContext *parent, const BlockDecl *bd, + const void *contextData) { ProfileCommon(ID, Block, ctx, parent, bd); + ID.AddPointer(contextData); } static bool classof(const LocationContext *Ctx) { @@ -359,6 +357,12 @@ public: const ScopeContext *getScope(AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s); + + const BlockInvocationContext * + getBlockInvocationContext(AnalysisDeclContext *ctx, + const LocationContext *parent, + const BlockDecl *BD, + const void *ContextData); /// Discard all previously created LocationContext objects. void clear(); @@ -383,7 +387,7 @@ public: ~AnalysisDeclContextManager(); - AnalysisDeclContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0); + AnalysisDeclContext *getContext(const Decl *D); bool getUseUnoptimizedCFG() const { return !cfgBuildOptions.PruneTriviallyFalseEdges; @@ -402,9 +406,8 @@ public: } // Get the top level stack frame. - const StackFrameContext *getStackFrame(Decl const *D, - idx::TranslationUnit *TU) { - return LocContexts.getStackFrame(getContext(D, TU), 0, 0, 0, 0); + const StackFrameContext *getStackFrame(const Decl *D) { + return LocContexts.getStackFrame(getContext(D), 0, 0, 0, 0); } // Get a stack frame with parent. @@ -416,7 +419,6 @@ public: return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx); } - /// Discard all previously created AnalysisDeclContexts. void clear(); diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index 27b22b8..4d087e7 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -21,10 +21,10 @@ #include "llvm/Support/Casting.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/BitVector.h" #include "clang/AST/Stmt.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/Basic/SourceLocation.h" +#include <bitset> #include <cassert> #include <iterator> @@ -277,6 +277,7 @@ class CFGBlock { typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; typedef ImplTy::iterator reverse_iterator; typedef ImplTy::const_iterator const_reverse_iterator; + typedef ImplTy::const_reference const_reference; void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); } reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E, @@ -284,8 +285,8 @@ class CFGBlock { return Impl.insert(I, Cnt, E, C); } - CFGElement front() const { return Impl.back(); } - CFGElement back() const { return Impl.front(); } + const_reference front() const { return Impl.back(); } + const_reference back() const { return Impl.front(); } iterator begin() { return Impl.rbegin(); } iterator end() { return Impl.rend(); } @@ -558,7 +559,7 @@ public: //===--------------------------------------------------------------------===// class BuildOptions { - llvm::BitVector alwaysAddMask; + std::bitset<Stmt::lastStmtConstant> alwaysAddMask; public: typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs; ForcedBlkExprs **forcedBlkExprs; @@ -583,8 +584,7 @@ public: } BuildOptions() - : alwaysAddMask(Stmt::lastStmtConstant, false) - ,forcedBlkExprs(0), PruneTriviallyFalseEdges(true) + : forcedBlkExprs(0), PruneTriviallyFalseEdges(true) ,AddEHEdges(false) ,AddInitializers(false) ,AddImplicitDtors(false) {} diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h index 9b68073..509de7b 100644 --- a/include/clang/Analysis/CallGraph.h +++ b/include/clang/Analysis/CallGraph.h @@ -26,7 +26,7 @@ namespace clang { class CallGraphNode; -/// \class The AST-based call graph. +/// \brief The AST-based call graph. /// /// The call graph extends itself with the given declarations by implementing /// the recursive AST visitor, which constructs the graph by visiting the given @@ -102,7 +102,8 @@ public: void dump() const; void viewGraph() const; - /// Part of recursive declaration visitation. + /// Part of recursive declaration visitation. We recursively visit all the + /// Declarations to collect the root functions. bool VisitFunctionDecl(FunctionDecl *FD) { // We skip function template definitions, as their semantics is // only determined when they are instantiated. @@ -121,6 +122,11 @@ public: return true; } + // We are only collecting the declarations, so do not step into the bodies. + bool TraverseStmt(Stmt *S) { return true; } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + private: /// \brief Add the given declaration to the call graph. void addNodeForDecl(Decl *D, bool IsGlobal); diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index aa7a33c..5de06cd 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -40,30 +40,36 @@ public: BlockEntranceKind, BlockExitKind, PreStmtKind, + PreStmtPurgeDeadSymbolsKind, + PostStmtPurgeDeadSymbolsKind, PostStmtKind, PreLoadKind, PostLoadKind, PreStoreKind, PostStoreKind, - PostPurgeDeadSymbolsKind, PostConditionKind, PostLValueKind, + MinPostStmtKind = PostStmtKind, + MaxPostStmtKind = PostLValueKind, PostInitializerKind, CallEnterKind, - CallExitKind, - MinPostStmtKind = PostStmtKind, - MaxPostStmtKind = CallExitKind, + CallExitBeginKind, + CallExitEndKind, + PreImplicitCallKind, + PostImplicitCallKind, + MinImplicitCallKind = PreImplicitCallKind, + MaxImplicitCallKind = PostImplicitCallKind, EpsilonKind}; private: - llvm::PointerIntPair<const void *, 2, unsigned> Data1; + const void *Data1; llvm::PointerIntPair<const void *, 2, unsigned> Data2; // The LocationContext could be NULL to allow ProgramPoint to be used in // context insensitive analysis. llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; - const ProgramPointTag *Tag; + llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag; ProgramPoint(); @@ -72,10 +78,10 @@ protected: Kind k, const LocationContext *l, const ProgramPointTag *tag = 0) - : Data1(P, ((unsigned) k) & 0x3), - Data2(0, (((unsigned) k) >> 2) & 0x3), - L(l, (((unsigned) k) >> 4) & 0x3), - Tag(tag) { + : Data1(P), + Data2(0, (((unsigned) k) >> 0) & 0x3), + L(l, (((unsigned) k) >> 2) & 0x3), + Tag(tag, (((unsigned) k) >> 4) & 0x3) { assert(getKind() == k); assert(getLocationContext() == l); assert(getData1() == P); @@ -86,13 +92,13 @@ protected: Kind k, const LocationContext *l, const ProgramPointTag *tag = 0) - : Data1(P1, ((unsigned) k) & 0x3), - Data2(P2, (((unsigned) k) >> 2) & 0x3), - L(l, (((unsigned) k) >> 4) & 0x3), - Tag(tag) {} + : Data1(P1), + Data2(P2, (((unsigned) k) >> 0) & 0x3), + L(l, (((unsigned) k) >> 2) & 0x3), + Tag(tag, (((unsigned) k) >> 4) & 0x3) {} protected: - const void *getData1() const { return Data1.getPointer(); } + const void *getData1() const { return Data1; } const void *getData2() const { return Data2.getPointer(); } void setData2(const void *d) { Data2.setPointer(d); } @@ -105,15 +111,23 @@ public: } Kind getKind() const { - unsigned x = L.getInt(); + unsigned x = Tag.getInt(); x <<= 2; - x |= Data2.getInt(); + x |= L.getInt(); x <<= 2; - x |= Data1.getInt(); + x |= Data2.getInt(); return (Kind) x; } - const ProgramPointTag *getTag() const { return Tag; } + /// \brief Is this a program point corresponding to purge/removal of dead + /// symbols and bindings. + bool isPurgeKind() { + Kind K = getKind(); + return (K == PostStmtPurgeDeadSymbolsKind || + K == PreStmtPurgeDeadSymbolsKind); + } + + const ProgramPointTag *getTag() const { return Tag.getPointer(); } const LocationContext *getLocationContext() const { return L.getPointer(); @@ -147,7 +161,7 @@ public: ID.AddPointer(getData1()); ID.AddPointer(getData2()); ID.AddPointer(getLocationContext()); - ID.AddPointer(Tag); + ID.AddPointer(getTag()); } static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, @@ -304,7 +318,7 @@ public: } }; -/// \class Represents a program point after a store evaluation. +/// \brief Represents a program point after a store evaluation. class PostStore : public PostStmt { public: /// Construct the post store point. @@ -340,14 +354,29 @@ public: } }; -class PostPurgeDeadSymbols : public PostStmt { +/// Represents a point after we ran remove dead bindings BEFORE +/// processing the given statement. +class PreStmtPurgeDeadSymbols : public StmtPoint { public: - PostPurgeDeadSymbols(const Stmt *S, const LocationContext *L, + PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag = 0) - : PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {} + : StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { } static bool classof(const ProgramPoint* Location) { - return Location->getKind() == PostPurgeDeadSymbolsKind; + return Location->getKind() == PreStmtPurgeDeadSymbolsKind; + } +}; + +/// Represents a point after we ran remove dead bindings AFTER +/// processing the given statement. +class PostStmtPurgeDeadSymbols : public StmtPoint { +public: + PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) + : StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostStmtPurgeDeadSymbolsKind; } }; @@ -383,11 +412,60 @@ public: } }; -class CallEnter : public StmtPoint { +/// Represents an implicit call event. +/// +/// The nearest statement is provided for diagnostic purposes. +class ImplicitCallPoint : public ProgramPoint { +public: + ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, + const LocationContext *L, const ProgramPointTag *Tag) + : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {} + + const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } + SourceLocation getLocation() const { + return SourceLocation::getFromPtrEncoding(getData1()); + } + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() >= MinImplicitCallKind && + Location->getKind() <= MaxImplicitCallKind; + } +}; + +/// Represents a program point just before an implicit call event. +/// +/// Explicit calls will appear as PreStmt program points. +class PreImplicitCall : public ImplicitCallPoint { +public: + PreImplicitCall(const Decl *D, SourceLocation Loc, + const LocationContext *L, const ProgramPointTag *Tag = 0) + : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == PreImplicitCallKind; + } +}; + +/// Represents a program point just after an implicit call event. +/// +/// Explicit calls will appear as PostStmt program points. +class PostImplicitCall : public ImplicitCallPoint { +public: + PostImplicitCall(const Decl *D, SourceLocation Loc, + const LocationContext *L, const ProgramPointTag *Tag = 0) + : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == PostImplicitCallKind; + } +}; + +/// Represents a point when we begin processing an inlined call. +class CallEnter : public ProgramPoint { public: CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, const LocationContext *callerCtx) - : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {} + : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {} const Stmt *getCallExpr() const { return static_cast<const Stmt *>(getData1()); @@ -402,14 +480,41 @@ public: } }; -class CallExit : public StmtPoint { +/// Represents a point when we start the call exit sequence (for inlined call). +/// +/// The call exit is simulated with a sequence of nodes, which occur between +/// CallExitBegin and CallExitEnd. The following operations occur between the +/// two program points: +/// - CallExitBegin +/// - Bind the return value +/// - Run Remove dead bindings (to clean up the dead symbols from the callee). +/// - CallExitEnd +class CallExitBegin : public ProgramPoint { +public: + // CallExitBegin uses the callee's location context. + CallExitBegin(const StackFrameContext *L) + : ProgramPoint(0, CallExitBeginKind, L, 0) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == CallExitBeginKind; + } +}; + +/// Represents a point when we finish the call exit sequence (for inlined call). +/// \sa CallExitBegin +class CallExitEnd : public ProgramPoint { public: - // CallExit uses the callee's location context. - CallExit(const Stmt *S, const LocationContext *L) - : StmtPoint(S, 0, CallExitKind, L, 0) {} + // CallExitEnd uses the caller's location context. + CallExitEnd(const StackFrameContext *CalleeCtx, + const LocationContext *CallerCtx) + : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, 0) {} + + const StackFrameContext *getCalleeContext() const { + return static_cast<const StackFrameContext *>(getData1()); + } static bool classof(const ProgramPoint *Location) { - return Location->getKind() == CallExitKind; + return Location->getKind() == CallExitEndKind; } }; diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index 97eb287..c510e20 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -69,6 +69,7 @@ public: DISPATCH_CASE(Field) DISPATCH_CASE(UsingDirective) DISPATCH_CASE(Using) + DISPATCH_CASE(NamespaceAlias) default: llvm_unreachable("Subtype of ScopedDecl not handled."); } @@ -90,6 +91,7 @@ public: DEFAULT_DISPATCH(ObjCCategory) DEFAULT_DISPATCH(UsingDirective) DEFAULT_DISPATCH(Using) + DEFAULT_DISPATCH(NamespaceAlias) void VisitCXXRecordDecl(CXXRecordDecl *D) { static_cast<ImplClass*>(this)->VisitRecordDecl(D); |