diff options
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r-- | include/clang/Analysis/Analyses/FormatString.h | 8 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/LiveVariables.h | 175 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/ReachableCode.h | 2 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/ThreadSafety.h | 153 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/UninitializedValues.h | 8 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisContext.h | 97 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Analysis/CFG.h | 154 | ||||
-rw-r--r-- | include/clang/Analysis/DomainSpecific/CocoaConventions.h | 11 | ||||
-rw-r--r-- | include/clang/Analysis/FlowSensitive/DataflowSolver.h | 62 | ||||
-rw-r--r-- | include/clang/Analysis/FlowSensitive/DataflowValues.h | 12 | ||||
-rw-r--r-- | include/clang/Analysis/ProgramPoint.h | 163 | ||||
-rw-r--r-- | include/clang/Analysis/Support/BlkExprDeclBitVector.h | 24 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h | 18 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtVisitor.h | 6 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGStmtVisitor.h | 22 |
16 files changed, 595 insertions, 322 deletions
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 7cc76a8d471bd..61f416447204c 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -164,8 +164,8 @@ public: return Position; } - llvm::StringRef getCharacters() const { - return llvm::StringRef(getStart(), getLength()); + StringRef getCharacters() const { + return StringRef(getStart(), getLength()); } bool consumesDataArgument() const { @@ -271,7 +271,7 @@ public: ArgTypeResult getArgType(ASTContext &Ctx) const; - void toString(llvm::raw_ostream &os) const; + void toString(raw_ostream &os) const; bool usesPositionalArg() const { return (bool) UsesPositionalArg; } unsigned getPositionalArgIndex() const { @@ -465,7 +465,7 @@ public: /// was not successful. bool fixType(QualType QT); - void toString(llvm::raw_ostream &os) const; + void toString(raw_ostream &os) const; // Validation methods - to check if any element results in undefined behavior bool hasValidPlusPrefix() const; diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index fbbd2613e7c2a..302ae1c41f95b 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -1,4 +1,4 @@ -//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-===// +//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-// // // The LLVM Compiler Infrastructure // @@ -14,110 +14,105 @@ #ifndef LLVM_CLANG_LIVEVARIABLES_H #define LLVM_CLANG_LIVEVARIABLES_H +#include "clang/Analysis/AnalysisContext.h" #include "clang/AST/Decl.h" -#include "clang/Analysis/Support/BlkExprDeclBitVector.h" -#include "clang/Analysis/FlowSensitive/DataflowValues.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/ImmutableSet.h" namespace clang { +class CFG; +class CFGBlock; class Stmt; class DeclRefExpr; class SourceManager; -class AnalysisContext; - -struct LiveVariables_ValueTypes { - - struct ObserverTy; - - // We keep dataflow state for declarations and block-level expressions; - typedef StmtDeclBitVector_Types::ValTy ValTy; - - // We need to keep track of both declarations and CFGBlock-level expressions, - // (so that we don't explore such expressions twice). We also want - // to compute liveness information for block-level expressions, since these - // act as "temporary" values. - - struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { - ObserverTy* Observer; - ValTy AlwaysLive; - AnalysisContext *AC; - bool killAtAssign; - - AnalysisDataTy() : Observer(NULL), AC(NULL), killAtAssign(true) {} + +class LiveVariables : public ManagedAnalysis { +public: + class LivenessValues { + public: + + llvm::ImmutableSet<const Stmt *> liveStmts; + llvm::ImmutableSet<const VarDecl *> liveDecls; + + bool equals(const LivenessValues &V) const; + + LivenessValues() + : liveStmts(0), liveDecls(0) {} + + LivenessValues(llvm::ImmutableSet<const Stmt *> LiveStmts, + llvm::ImmutableSet<const VarDecl *> LiveDecls) + : liveStmts(LiveStmts), liveDecls(LiveDecls) {} + + ~LivenessValues() {} + + bool isLive(const Stmt *S) const; + bool isLive(const VarDecl *D) const; + + friend class LiveVariables; }; - - //===-----------------------------------------------------===// - // ObserverTy - Observer for uninitialized values queries. - //===-----------------------------------------------------===// - - struct ObserverTy { - virtual ~ObserverTy() {} - - /// ObserveStmt - A callback invoked right before invoking the + + struct Observer { + virtual ~Observer() {} + + /// A callback invoked right before invoking the /// liveness transfer function on the given statement. - virtual void ObserveStmt(Stmt* S, const CFGBlock *currentBlock, - const AnalysisDataTy& AD, - const ValTy& V) {} - - virtual void ObserverKill(DeclRefExpr* DR) {} - }; -}; - -class LiveVariables : public DataflowValues<LiveVariables_ValueTypes, - dataflow::backward_analysis_tag> { - - -public: - typedef LiveVariables_ValueTypes::ObserverTy ObserverTy; - - LiveVariables(AnalysisContext &AC, bool killAtAssign = true); - - /// IsLive - Return true if a variable is live at the end of a + virtual void observeStmt(const Stmt *S, + const CFGBlock *currentBlock, + const LivenessValues& V) {} + + /// Called when the live variables analysis registers + /// that a variable is killed. + virtual void observerKill(const DeclRefExpr *DR) {} + }; + + + virtual ~LiveVariables(); + + /// Compute the liveness information for a given CFG. + static LiveVariables *computeLiveness(AnalysisContext &analysisContext, + bool killAtAssign); + + /// Return true if a variable is live at the end of a /// specified block. - bool isLive(const CFGBlock* B, const VarDecl* D) const; - - /// IsLive - Returns true if a variable is live at the beginning of the + bool isLive(const CFGBlock *B, const VarDecl *D); + + /// Returns true if a variable is live at the beginning of the /// the statement. This query only works if liveness information /// has been recorded at the statement level (see runOnAllBlocks), and /// only returns liveness information for block-level expressions. - bool isLive(const Stmt* S, const VarDecl* D) const; - - /// IsLive - Returns true the block-level expression "value" is live + bool isLive(const Stmt *S, const VarDecl *D); + + /// Returns true the block-level expression "value" is live /// before the given block-level expression (see runOnAllBlocks). - bool isLive(const Stmt* Loc, const Stmt* StmtVal) const; - - /// IsLive - Return true if a variable is live according to the - /// provided livness bitvector. - bool isLive(const ValTy& V, const VarDecl* D) const; - - /// dumpLiveness - Print to stderr the liveness information encoded - /// by a specified bitvector. - void dumpLiveness(const ValTy& V, const SourceManager& M) const; - - /// dumpBlockLiveness - Print to stderr the liveness information - /// associated with each basic block. - void dumpBlockLiveness(const SourceManager& M) const; - - /// getNumDecls - Return the number of variables (declarations) that - /// whose liveness status is being tracked by the dataflow - /// analysis. - unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); } - - /// IntializeValues - This routine can perform extra initialization, but - /// for LiveVariables this does nothing since all that logic is in - /// the constructor. - void InitializeValues(const CFG& cfg) {} - - void runOnCFG(CFG& cfg); - - /// runOnAllBlocks - Propagate the dataflow values once for each block, - /// starting from the current dataflow values. 'recordStmtValues' indicates - /// whether the method should store dataflow values per each individual - /// block-level expression. - void runOnAllBlocks(const CFG& cfg, ObserverTy* Obs, - bool recordStmtValues=false); + bool isLive(const Stmt *Loc, const Stmt *StmtVal); + + /// Print to stderr the liveness information associated with + /// each basic block. + void dumpBlockLiveness(const SourceManager& M); + + void runOnAllBlocks(Observer &obs); + + static LiveVariables *create(AnalysisContext &analysisContext) { + return computeLiveness(analysisContext, true); + } + + static const void *getTag(); + +private: + LiveVariables(void *impl); + void *impl; }; - + +class RelaxedLiveVariables : public LiveVariables { +public: + static LiveVariables *create(AnalysisContext &analysisContext) { + return computeLiveness(analysisContext, false); + } + + static const void *getTag(); +}; + } // end namespace clang #endif diff --git a/include/clang/Analysis/Analyses/ReachableCode.h b/include/clang/Analysis/Analyses/ReachableCode.h index e0c84f97fd334..6cf7fa42ff45e 100644 --- a/include/clang/Analysis/Analyses/ReachableCode.h +++ b/include/clang/Analysis/Analyses/ReachableCode.h @@ -45,7 +45,7 @@ public: /// ScanReachableFromBlock - Mark all blocks reachable from Start. /// Returns the total number of blocks that were marked reachable. -unsigned ScanReachableFromBlock(const CFGBlock &Start, +unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable); void FindUnreachableCode(AnalysisContext &AC, Callback &CB); diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h new file mode 100644 index 0000000000000..a32505624a226 --- /dev/null +++ b/include/clang/Analysis/Analyses/ThreadSafety.h @@ -0,0 +1,153 @@ +//===- ThreadSafety.h ------------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// A intra-procedural analysis for thread safety (e.g. deadlocks and race +// conditions), based off of an annotation system. +// +// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more +// information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_THREADSAFETY_H +#define LLVM_CLANG_THREADSAFETY_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace thread_safety { + +/// This enum distinguishes between different kinds of operations that may +/// need to be protected by locks. We use this enum in error handling. +enum ProtectedOperationKind { + POK_VarDereference, /// Dereferencing a variable (e.g. p in *p = 5;) + POK_VarAccess, /// Reading or writing a variable (e.g. x in x = 5;) + POK_FunctionCall /// Making a function call (e.g. fool()) +}; + +/// This enum distinguishes between different kinds of lock actions. For +/// example, it is an error to write a variable protected by shared version of a +/// mutex. +enum LockKind { + LK_Shared, /// Shared/reader lock of a mutex + LK_Exclusive /// Exclusive/writer lock of a mutex +}; + +/// This enum distinguishes between different ways to access (read or write) a +/// variable. +enum AccessKind { + AK_Read, /// Reading a variable + AK_Written /// Writing a variable +}; + +/// This enum distinguishes between different situations where we warn due to +/// inconsistent locking. +/// \enum SK_LockedSomeLoopIterations -- a mutex is locked for some but not all +/// loop iterations. +/// \enum SK_LockedSomePredecessors -- a mutex is locked in some but not all +/// predecessors of a CFGBlock. +/// \enum SK_LockedAtEndOfFunction -- a mutex is still locked at the end of a +/// function. +enum LockErrorKind { + LEK_LockedSomeLoopIterations, + LEK_LockedSomePredecessors, + LEK_LockedAtEndOfFunction +}; + +/// Handler class for thread safety warnings. +class ThreadSafetyHandler { +public: + typedef llvm::StringRef Name; + virtual ~ThreadSafetyHandler() = 0; + + /// Warn about lock expressions which fail to resolve to lockable objects. + /// \param Loc -- the SourceLocation of the unresolved expression. + virtual void handleInvalidLockExp(SourceLocation Loc) {} + + /// Warn about unlock function calls that do not have a prior matching lock + /// expression. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The SourceLocation of the Unlock + virtual void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) {} + + /// Warn about lock function calls for locks which are already held. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The location of the second lock expression. + virtual void handleDoubleLock(Name LockName, SourceLocation Loc) {} + + /// Warn about situations where a mutex is sometimes held and sometimes not. + /// The three situations are: + /// 1. a mutex is locked on an "if" branch but not the "else" branch, + /// 2, or a mutex is only held at the start of some loop iterations, + /// 3. or when a mutex is locked but not unlocked inside a function. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The location of the lock expression where the mutex is locked + /// \param LEK -- which of the three above cases we should warn for + virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc, + LockErrorKind LEK){} + + /// Warn when a mutex is held exclusively and shared at the same point. For + /// example, if a mutex is locked exclusively during an if branch and shared + /// during the else branch. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc1 -- The location of the first lock expression. + /// \param Loc2 -- The location of the second lock expression. + virtual void handleExclusiveAndShared(Name LockName, SourceLocation Loc1, + SourceLocation Loc2) {} + + /// Warn when a protected operation occurs while no locks are held. + /// \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 Loc -- The location of the protected operation. + virtual void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK, + AccessKind AK, SourceLocation Loc) {} + + /// 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 Loc -- The location of the protected operation. + virtual void handleMutexNotHeld(const NamedDecl *D, + ProtectedOperationKind POK, Name LockName, + LockKind LK, SourceLocation Loc) {} + + /// Warn when a function is called while an excluded mutex is locked. For + /// example, the mutex may be locked inside the function. + /// \param FunName -- The name of the function + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The location of the function call. + virtual void handleFunExcludesLock(Name FunName, Name LockName, + SourceLocation Loc) {} +}; + +/// \brief Check a function's CFG for thread-safety violations. +/// +/// We traverse the blocks in the CFG, compute the set of mutexes that are held +/// at the end of each block, and issue warnings for thread safety violations. +/// Each block in the CFG is traversed exactly once. +void runThreadSafetyAnalysis(AnalysisContext &AC, ThreadSafetyHandler &Handler); + +/// \brief Helper function that returns a LockKind required for the given level +/// of access. +LockKind getLockKindFromAccessKind(AccessKind AK); + +}} // end namespace clang::thread_safety +#endif diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index badb493a9df4e..e2e4f35043eec 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -27,10 +27,16 @@ 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) {} + + /// Called when the uninitialized variable analysis detects the + /// idiom 'int x = x'. All other uses of 'x' within the initializer + /// are handled by handleUseOfUninitVariable. + virtual void handleSelfInit(const VarDecl *vd) {} }; struct UninitVariablesAnalysisStats { diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 6a1876e659008..3d0e88a51d8af 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/DenseMap.h" @@ -31,14 +32,35 @@ class Stmt; class CFGReverseBlockReachabilityAnalysis; class CFGStmtMap; class LiveVariables; +class ManagedAnalysis; class ParentMap; class PseudoConstantAnalysis; class ImplicitParamDecl; class LocationContextManager; class StackFrameContext; - + namespace idx { class TranslationUnit; } +/// The base class of a hierarchy of objects representing analyses tied +/// to AnalysisContext. +class ManagedAnalysis { +protected: + ManagedAnalysis() {} +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(AnalysisContext &Ctx); + // + // which creates the analysis object given an AnalysisContext. +}; + /// AnalysisContext contains the context data for the function or method under /// analysis. class AnalysisContext { @@ -54,7 +76,6 @@ class AnalysisContext { CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs; bool builtCFG, builtCompleteCFG; - const bool useUnoptimizedCFG; llvm::OwningPtr<LiveVariables> liveness; llvm::OwningPtr<LiveVariables> relaxedLiveness; @@ -67,12 +88,13 @@ class AnalysisContext { // FIXME: remove. llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars; + void *ManagedAnalyses; + public: + AnalysisContext(const Decl *d, idx::TranslationUnit *tu); + AnalysisContext(const Decl *d, idx::TranslationUnit *tu, - bool useUnoptimizedCFG = false, - bool addehedges = false, - bool addImplicitDtors = false, - bool addInitializers = false); + const CFG::BuildOptions &buildOptions); ~AnalysisContext(); @@ -81,13 +103,22 @@ public: idx::TranslationUnit *getTranslationUnit() const { return TU; } + /// Return the build options used to construct the CFG. + CFG::BuildOptions &getCFGBuildOptions() { + return cfgBuildOptions; + } + + const CFG::BuildOptions &getCFGBuildOptions() const { + return cfgBuildOptions; + } + /// getAddEHEdges - Return true iff we are adding exceptional 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; + return !cfgBuildOptions.PruneTriviallyFalseEdges; } bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; } bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; } @@ -95,7 +126,7 @@ public: void registerForcedBlockExpression(const Stmt *stmt); const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); - Stmt *getBody(); + Stmt *getBody() const; CFG *getCFG(); CFGStmtMap *getCFGStmtMap(); @@ -114,8 +145,6 @@ public: ParentMap &getParentMap(); PseudoConstantAnalysis *getPseudoConstantAnalysis(); - LiveVariables *getLiveVariables(); - LiveVariables *getRelaxedLiveVariables(); typedef const VarDecl * const * referenced_decls_iterator; @@ -125,29 +154,44 @@ public: /// Return the ImplicitParamDecl* associated with 'self' if this /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. const ImplicitParamDecl *getSelfDecl() const; + + /// Return the specified analysis object, lazily running the analysis if + /// necessary. Return NULL if the analysis could not run. + template <typename T> + T *getAnalysis() { + const void *tag = T::getTag(); + ManagedAnalysis *&data = getAnalysisImpl(tag); + if (!data) { + data = T::create(*this); + } + return static_cast<T*>(data); + } +private: + ManagedAnalysis *&getAnalysisImpl(const void* tag); }; class AnalysisContextManager { typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap; ContextMap Contexts; - bool UseUnoptimizedCFG; - bool AddImplicitDtors; - bool AddInitializers; + CFG::BuildOptions cfgBuildOptions; public: AnalysisContextManager(bool useUnoptimizedCFG = false, - bool addImplicitDtors = false, bool addInitializers = false) - : UseUnoptimizedCFG(useUnoptimizedCFG), AddImplicitDtors(addImplicitDtors), - AddInitializers(addInitializers) {} + bool addImplicitDtors = false, + bool addInitializers = false); ~AnalysisContextManager(); AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0); - bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; } - bool getAddImplicitDtors() const { return AddImplicitDtors; } - bool getAddInitializers() const { return AddInitializers; } + bool getUseUnoptimizedCFG() const { + return !cfgBuildOptions.PruneTriviallyFalseEdges; + } + + CFG::BuildOptions &getCFGBuildOptions() { + return cfgBuildOptions; + } - // Discard all previously created AnalysisContexts. + /// Discard all previously created AnalysisContexts. void clear(); }; @@ -187,8 +231,9 @@ public: CFG *getCFG() const { return getAnalysisContext()->getCFG(); } - LiveVariables *getLiveVariables() const { - return getAnalysisContext()->getLiveVariables(); + template <typename T> + T *getAnalysis() const { + return getAnalysisContext()->getAnalysis<T>(); } ParentMap &getParentMap() const { @@ -212,7 +257,7 @@ public: ContextKind ck, AnalysisContext *ctx, const LocationContext *parent, - const void* data); + const void *data); }; class StackFrameContext : public LocationContext { @@ -251,7 +296,7 @@ public: ID.AddInteger(idx); } - static bool classof(const LocationContext* Ctx) { + static bool classof(const LocationContext *Ctx) { return Ctx->getKind() == StackFrame; } }; @@ -274,7 +319,7 @@ public: ProfileCommon(ID, Scope, ctx, parent, s); } - static bool classof(const LocationContext* Ctx) { + static bool classof(const LocationContext *Ctx) { return Ctx->getKind() == Scope; } }; @@ -302,7 +347,7 @@ public: ProfileCommon(ID, Block, ctx, parent, bd); } - static bool classof(const LocationContext* Ctx) { + static bool classof(const LocationContext *Ctx) { return Ctx->getKind() == Block; } }; diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index dbf4e4c9aefeb..16d31b476423b 100644 --- a/include/clang/Analysis/AnalysisDiagnostic.h +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -16,7 +16,7 @@ namespace clang { namespace diag { enum { #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ - SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM, + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM, #define ANALYSISSTART #include "clang/Basic/DiagnosticAnalysisKinds.inc" #undef DIAG diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index ca46459afd9a8..f191c802818be 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -21,15 +21,13 @@ #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 <cassert> #include <iterator> -namespace llvm { - class raw_ostream; -} - namespace clang { class CXXDestructorDecl; class Decl; @@ -98,7 +96,9 @@ class CFGStmt : public CFGElement { public: CFGStmt(Stmt *S) : CFGElement(Statement, S) {} - Stmt *getStmt() const { return static_cast<Stmt *>(Data1.getPointer()); } + const Stmt *getStmt() const { + return static_cast<const Stmt *>(Data1.getPointer()); + } static bool classof(const CFGElement *E) { return E->getKind() == Statement; @@ -280,7 +280,7 @@ class CFGBlock { void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); } reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E, - BumpVectorContext& C) { + BumpVectorContext &C) { return Impl.insert(I, Cnt, E, C); } @@ -333,10 +333,21 @@ class CFGBlock { AdjacentBlocks Preds; AdjacentBlocks Succs; + /// NoReturn - This bit is set when the basic block contains a function call + /// or implicit destructor that is attributed as 'noreturn'. In that case, + /// control cannot technically ever proceed past this block. All such blocks + /// will have a single immediate successor: the exit block. This allows them + /// to be easily reached from the exit block and using this bit quickly + /// recognized without scanning the contents of the block. + /// + /// Optimization Note: This bit could be profitably folded with Terminator's + /// storage if the memory usage of CFGBlock becomes an issue. + unsigned HasNoReturnElement : 1; + public: explicit CFGBlock(unsigned blockid, BumpVectorContext &C) : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), - BlockID(blockid), Preds(C, 1), Succs(C, 1) {} + BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false) {} ~CFGBlock() {} // Statement iterators @@ -455,42 +466,45 @@ public: // Manipulation of block contents - void setTerminator(Stmt* Statement) { Terminator = Statement; } - void setLabel(Stmt* Statement) { Label = Statement; } + void setTerminator(Stmt *Statement) { Terminator = Statement; } + void setLabel(Stmt *Statement) { Label = Statement; } void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; } + void setHasNoReturnElement() { HasNoReturnElement = true; } CFGTerminator getTerminator() { return Terminator; } const CFGTerminator getTerminator() const { return Terminator; } - Stmt* getTerminatorCondition(); + Stmt *getTerminatorCondition(); - const Stmt* getTerminatorCondition() const { + const Stmt *getTerminatorCondition() const { return const_cast<CFGBlock*>(this)->getTerminatorCondition(); } const Stmt *getLoopTarget() const { return LoopTarget; } - Stmt* getLabel() { return Label; } - const Stmt* getLabel() const { return Label; } + Stmt *getLabel() { return Label; } + const Stmt *getLabel() const { return Label; } + + bool hasNoReturnElement() const { return HasNoReturnElement; } unsigned getBlockID() const { return BlockID; } void dump(const CFG *cfg, const LangOptions &LO) const; - void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const; - void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const; + void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const; + void printTerminator(raw_ostream &OS, const LangOptions &LO) const; - void addSuccessor(CFGBlock* Block, BumpVectorContext &C) { + void addSuccessor(CFGBlock *Block, BumpVectorContext &C) { if (Block) Block->Preds.push_back(this, C); Succs.push_back(Block, C); } - void appendStmt(Stmt* statement, BumpVectorContext &C) { + void appendStmt(Stmt *statement, BumpVectorContext &C) { Elements.push_back(CFGStmt(statement), C); } void appendInitializer(CXXCtorInitializer *initializer, - BumpVectorContext& C) { + BumpVectorContext &C) { Elements.push_back(CFGInitializer(initializer), C); } @@ -506,14 +520,18 @@ public: Elements.push_back(CFGTemporaryDtor(E), C); } + void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) { + Elements.push_back(CFGAutomaticObjDtor(VD, S), C); + } + // Destructors must be inserted in reversed order. So insertion is in two // steps. First we prepare space for some number of elements, then we insert // the elements beginning at the last position in prepared space. iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt, - BumpVectorContext& C) { + BumpVectorContext &C) { return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C)); } - iterator insertAutomaticObjDtor(iterator I, VarDecl* VD, Stmt* S) { + iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) { *I = CFGAutomaticObjDtor(VD, S); return ++I; } @@ -533,30 +551,46 @@ public: //===--------------------------------------------------------------------===// class BuildOptions { + llvm::BitVector alwaysAddMask; public: typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs; ForcedBlkExprs **forcedBlkExprs; - bool PruneTriviallyFalseEdges:1; - bool AddEHEdges:1; - bool AddInitializers:1; - bool AddImplicitDtors:1; + bool PruneTriviallyFalseEdges; + bool AddEHEdges; + bool AddInitializers; + bool AddImplicitDtors; + + bool alwaysAdd(const Stmt *stmt) const { + return alwaysAddMask[stmt->getStmtClass()]; + } + + BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) { + alwaysAddMask[stmtClass] = val; + return *this; + } + + BuildOptions &setAllAlwaysAdd() { + alwaysAddMask.set(); + return *this; + } BuildOptions() - : forcedBlkExprs(0), PruneTriviallyFalseEdges(true) - , AddEHEdges(false) - , AddInitializers(false) - , AddImplicitDtors(false) {} + : alwaysAddMask(Stmt::lastStmtConstant, false) + ,forcedBlkExprs(0), PruneTriviallyFalseEdges(true) + ,AddEHEdges(false) + ,AddInitializers(false) + ,AddImplicitDtors(false) {} }; /// buildCFG - Builds a CFG from an AST. The responsibility to free the /// constructed CFG belongs to the caller. - static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C, + static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C, const BuildOptions &BO); /// createBlock - Create a new block in the CFG. The CFG owns the block; /// the caller should not directly free it. - CFGBlock* createBlock(); + CFGBlock *createBlock(); /// setEntry - Set the entry block of the CFG. This is typically used /// only during CFG construction. Most CFG clients expect that the @@ -565,7 +599,7 @@ public: /// setIndirectGotoBlock - Set the block used for indirect goto jumps. /// This is typically used only during CFG construction. - void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; } + void setIndirectGotoBlock(CFGBlock *B) { IndirectGotoBlock = B; } //===--------------------------------------------------------------------===// // Block Iterators @@ -577,8 +611,8 @@ public: typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - CFGBlock& front() { return *Blocks.front(); } - CFGBlock& back() { return *Blocks.back(); } + CFGBlock & front() { return *Blocks.front(); } + CFGBlock & back() { return *Blocks.back(); } iterator begin() { return Blocks.begin(); } iterator end() { return Blocks.end(); } @@ -590,13 +624,25 @@ public: const_reverse_iterator rbegin() const { return Blocks.rbegin(); } const_reverse_iterator rend() const { return Blocks.rend(); } - CFGBlock& getEntry() { return *Entry; } - const CFGBlock& getEntry() const { return *Entry; } - CFGBlock& getExit() { return *Exit; } - const CFGBlock& getExit() const { return *Exit; } + CFGBlock & getEntry() { return *Entry; } + const CFGBlock & getEntry() const { return *Entry; } + CFGBlock & getExit() { return *Exit; } + const CFGBlock & getExit() const { return *Exit; } - CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; } - const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; } + CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; } + const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; } + + typedef std::vector<const CFGBlock*>::const_iterator try_block_iterator; + try_block_iterator try_blocks_begin() const { + return TryDispatchBlocks.begin(); + } + try_block_iterator try_blocks_end() const { + return TryDispatchBlocks.end(); + } + + void addTryDispatchBlock(const CFGBlock *block) { + TryDispatchBlocks.push_back(block); + } //===--------------------------------------------------------------------===// // Member templates useful for various batch operations over CFGs. @@ -608,7 +654,7 @@ public: for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end(); BI != BE; ++BI) { if (const CFGStmt *stmt = BI->getAs<CFGStmt>()) - O(stmt->getStmt()); + O(const_cast<Stmt*>(stmt->getStmt())); } } @@ -624,11 +670,11 @@ public: operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; } }; - bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); } + bool isBlkExpr(const Stmt *S) { return getBlkExprNum(S); } bool isBlkExpr(const Stmt *S) const { return const_cast<CFG*>(this)->isBlkExpr(S); } - BlkExprNumTy getBlkExprNum(const Stmt* S); + BlkExprNumTy getBlkExprNum(const Stmt *S); unsigned getNumBlkExprs(); /// getNumBlockIDs - Returns the total number of BlockIDs allocated (which @@ -640,7 +686,7 @@ public: //===--------------------------------------------------------------------===// void viewCFG(const LangOptions &LO) const; - void print(llvm::raw_ostream& OS, const LangOptions &LO) const; + void print(raw_ostream &OS, const LangOptions &LO) const; void dump(const LangOptions &LO) const; //===--------------------------------------------------------------------===// @@ -661,8 +707,8 @@ public: } private: - CFGBlock* Entry; - CFGBlock* Exit; + CFGBlock *Entry; + CFGBlock *Exit; CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch // for indirect gotos unsigned NumBlockIDs; @@ -670,11 +716,15 @@ private: // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h. // It represents a map from Expr* to integers to record the set of // block-level expressions and their "statement number" in the CFG. - void* BlkExprMap; + void * BlkExprMap; BumpVectorContext BlkBVC; CFGBlockListTy Blocks; + + /// C++ 'try' statements are modeled with an indirect dispatch block. + /// This is the collection of such blocks present in the CFG. + std::vector<const CFGBlock *> TryDispatchBlocks; }; } // end namespace clang @@ -703,11 +753,11 @@ template <> struct simplify_type< ::clang::CFGTerminator> { // Traits for: CFGBlock -template <> struct GraphTraits< ::clang::CFGBlock* > { +template <> struct GraphTraits< ::clang::CFGBlock *> { typedef ::clang::CFGBlock NodeType; typedef ::clang::CFGBlock::succ_iterator ChildIteratorType; - static NodeType* getEntryNode(::clang::CFGBlock* BB) + static NodeType* getEntryNode(::clang::CFGBlock *BB) { return BB; } static inline ChildIteratorType child_begin(NodeType* N) @@ -717,11 +767,11 @@ template <> struct GraphTraits< ::clang::CFGBlock* > { { return N->succ_end(); } }; -template <> struct GraphTraits< const ::clang::CFGBlock* > { +template <> struct GraphTraits< const ::clang::CFGBlock *> { typedef const ::clang::CFGBlock NodeType; typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType; - static NodeType* getEntryNode(const clang::CFGBlock* BB) + static NodeType* getEntryNode(const clang::CFGBlock *BB) { return BB; } static inline ChildIteratorType child_begin(NodeType* N) @@ -748,7 +798,7 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > { // Traits for: CFG template <> struct GraphTraits< ::clang::CFG* > - : public GraphTraits< ::clang::CFGBlock* > { + : public GraphTraits< ::clang::CFGBlock *> { typedef ::clang::CFG::iterator nodes_iterator; @@ -758,7 +808,7 @@ template <> struct GraphTraits< ::clang::CFG* > }; template <> struct GraphTraits<const ::clang::CFG* > - : public GraphTraits<const ::clang::CFGBlock* > { + : public GraphTraits<const ::clang::CFGBlock *> { typedef ::clang::CFG::const_iterator nodes_iterator; diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h index 5a4e06ff53e57..fa8afccfcd895 100644 --- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h +++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -14,12 +14,13 @@ #ifndef LLVM_CLANG_ANALYSIS_DS_COCOA #define LLVM_CLANG_ANALYSIS_DS_COCOA +#include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/StringRef.h" -#include "clang/AST/Type.h" namespace clang { - +class FunctionDecl; class ObjCMethodDecl; +class QualType; namespace ento { namespace cocoa { @@ -33,8 +34,8 @@ namespace cocoa { return deriveNamingConvention(S, MD) == CreateRule; } - bool isRefType(QualType RetTy, llvm::StringRef Prefix, - llvm::StringRef Name = llvm::StringRef()); + bool isRefType(QualType RetTy, StringRef Prefix, + StringRef Name = StringRef()); bool isCocoaObjectRef(QualType T); @@ -43,7 +44,7 @@ namespace cocoa { namespace coreFoundation { bool isCFObjectRef(QualType T); - bool followsCreateRule(llvm::StringRef functionName); + bool followsCreateRule(const FunctionDecl *FD); } }} // end: "clang:ento" diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h index 9561b964b5f8f..017da636ebf61 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h +++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -30,11 +30,11 @@ namespace clang { class DataflowWorkListTy { llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet; - llvm::SmallVector<const CFGBlock *, 10> BlockQueue; + SmallVector<const CFGBlock *, 10> BlockQueue; public: /// enqueue - Add a block to the worklist. Blocks already on the /// worklist are not added a second time. - void enqueue(const CFGBlock* B) { + void enqueue(const CFGBlock *B) { unsigned char &x = BlockSet[B]; if (x == 1) return; @@ -43,7 +43,7 @@ public: } /// dequeue - Remove a block from the worklist. - const CFGBlock* dequeue() { + const CFGBlock *dequeue() { assert(!BlockQueue.empty()); const CFGBlock *B = BlockQueue.back(); BlockQueue.pop_back(); @@ -69,20 +69,20 @@ template <> struct ItrTraits<forward_analysis_tag> { typedef CFGBlock::const_succ_iterator NextBItr; typedef CFGBlock::const_iterator StmtItr; - static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); } - static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); } + static PrevBItr PrevBegin(const CFGBlock *B) { return B->pred_begin(); } + static PrevBItr PrevEnd(const CFGBlock *B) { return B->pred_end(); } - static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); } - static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); } + static NextBItr NextBegin(const CFGBlock *B) { return B->succ_begin(); } + static NextBItr NextEnd(const CFGBlock *B) { return B->succ_end(); } - static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); } - static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); } + static StmtItr StmtBegin(const CFGBlock *B) { return B->begin(); } + static StmtItr StmtEnd(const CFGBlock *B) { return B->end(); } - static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { + static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) { return BlockEdge(Prev, B, 0); } - static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { + static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) { return BlockEdge(B, Next, 0); } }; @@ -92,20 +92,20 @@ template <> struct ItrTraits<backward_analysis_tag> { typedef CFGBlock::const_pred_iterator NextBItr; typedef CFGBlock::const_reverse_iterator StmtItr; - static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); } - static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); } + static PrevBItr PrevBegin(const CFGBlock *B) { return B->succ_begin(); } + static PrevBItr PrevEnd(const CFGBlock *B) { return B->succ_end(); } - static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); } - static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); } + static NextBItr NextBegin(const CFGBlock *B) { return B->pred_begin(); } + static NextBItr NextEnd(const CFGBlock *B) { return B->pred_end(); } - static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); } - static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); } + static StmtItr StmtBegin(const CFGBlock *B) { return B->rbegin(); } + static StmtItr StmtEnd(const CFGBlock *B) { return B->rend(); } - static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) { + static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) { return BlockEdge(B, Prev, 0); } - static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) { + static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) { return BlockEdge(Next, B, 0); } }; @@ -162,7 +162,7 @@ public: /// dataflow values using runOnCFG, as runOnBlock is intended to /// only be used for querying the dataflow values within a block /// with and Observer object. - void runOnBlock(const CFGBlock* B, bool recordStmtValues) { + void runOnBlock(const CFGBlock *B, bool recordStmtValues) { BlockDataMapTy& M = D.getBlockDataMap(); typename BlockDataMapTy::iterator I = M.find(B); @@ -172,13 +172,13 @@ public: } } - void runOnBlock(const CFGBlock& B, bool recordStmtValues) { + void runOnBlock(const CFGBlock &B, bool recordStmtValues) { runOnBlock(&B, recordStmtValues); } - void runOnBlock(CFG::iterator& I, bool recordStmtValues) { + void runOnBlock(CFG::iterator &I, bool recordStmtValues) { runOnBlock(*I, recordStmtValues); } - void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) { + void runOnBlock(CFG::const_iterator &I, bool recordStmtValues) { runOnBlock(*I, recordStmtValues); } @@ -199,7 +199,7 @@ private: EnqueueBlocksOnWorklist(cfg, AnalysisDirTag()); while (!WorkList.isEmpty()) { - const CFGBlock* B = WorkList.dequeue(); + const CFGBlock *B = WorkList.dequeue(); ProcessMerge(cfg, B); ProcessBlock(B, recordStmtValues, AnalysisDirTag()); UpdateEdges(cfg, B, TF.getVal()); @@ -222,7 +222,7 @@ private: WorkList.enqueue(&**I); } - void ProcessMerge(CFG& cfg, const CFGBlock* B) { + void ProcessMerge(CFG& cfg, const CFGBlock *B) { ValTy& V = TF.getVal(); TF.SetTopValue(V); @@ -270,7 +270,7 @@ private: } /// ProcessBlock - Process the transfer functions for a given block. - void ProcessBlock(const CFGBlock* B, bool recordStmtValues, + void ProcessBlock(const CFGBlock *B, bool recordStmtValues, dataflow::forward_analysis_tag) { TF.setCurrentBlock(B); @@ -284,7 +284,7 @@ private: TF.VisitTerminator(const_cast<CFGBlock*>(B)); } - void ProcessBlock(const CFGBlock* B, bool recordStmtValues, + void ProcessBlock(const CFGBlock *B, bool recordStmtValues, dataflow::backward_analysis_tag) { TF.setCurrentBlock(B); @@ -298,12 +298,12 @@ private: } } - void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) { + void ProcessStmt(const Stmt *S, bool record, dataflow::forward_analysis_tag) { if (record) D.getStmtDataMap()[S] = TF.getVal(); TF.BlockStmt_Visit(const_cast<Stmt*>(S)); } - void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){ + void ProcessStmt(const Stmt *S, bool record, dataflow::backward_analysis_tag){ TF.BlockStmt_Visit(const_cast<Stmt*>(S)); if (record) D.getStmtDataMap()[S] = TF.getVal(); } @@ -312,14 +312,14 @@ private: /// block, update the dataflow value associated with the block's /// outgoing/incoming edges (depending on whether we do a // forward/backward analysis respectively) - void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) { + void UpdateEdges(CFG& cfg, const CFGBlock *B, ValTy& V) { for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I) if (CFGBlock *NextBlk = *I) UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk); } /// UpdateEdgeValue - Update the value associated with a given edge. - void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) { + void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock *TargetBlock) { EdgeDataMapTy& M = D.getEdgeDataMap(); typename EdgeDataMapTy::iterator I = M.find(E); diff --git a/include/clang/Analysis/FlowSensitive/DataflowValues.h b/include/clang/Analysis/FlowSensitive/DataflowValues.h index 7aa15c5b40efa..f86b2b0bfea17 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowValues.h +++ b/include/clang/Analysis/FlowSensitive/DataflowValues.h @@ -84,13 +84,13 @@ public: /// getEdgeData - Retrieves the dataflow values associated with a /// CFG edge. - ValTy& getEdgeData(const BlockEdge& E) { + ValTy& getEdgeData(const BlockEdge &E) { typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E); assert (I != EdgeDataMap.end() && "No data associated with Edge."); return I->second; } - const ValTy& getEdgeData(const BlockEdge& E) const { + const ValTy& getEdgeData(const BlockEdge &E) const { return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E); } @@ -98,13 +98,13 @@ public: /// specified CFGBlock. If the dataflow analysis is a forward analysis, /// this data is associated with the END of the block. If the analysis /// is a backwards analysis, it is associated with the ENTRY of the block. - ValTy& getBlockData(const CFGBlock* B) { + ValTy& getBlockData(const CFGBlock *B) { typename BlockDataMapTy::iterator I = BlockDataMap.find(B); assert (I != BlockDataMap.end() && "No data associated with block."); return I->second; } - const ValTy& getBlockData(const CFGBlock* B) const { + const ValTy& getBlockData(const CFGBlock *B) const { return const_cast<DataflowValues*>(this)->getBlockData(B); } @@ -114,14 +114,14 @@ public: /// If the analysis is a backwards analysis, it is associated with /// the point after a Stmt. This data is only computed for block-level /// expressions, and only when requested when the analysis is executed. - ValTy& getStmtData(const Stmt* S) { + ValTy& getStmtData(const Stmt *S) { assert (StmtDataMap && "Dataflow values were not computed for statements."); typename StmtDataMapTy::iterator I = StmtDataMap->find(S); assert (I != StmtDataMap->end() && "No data associated with statement."); return I->second; } - const ValTy& getStmtData(const Stmt* S) const { + const ValTy& getStmtData(const Stmt *S) const { return const_cast<DataflowValues*>(this)->getStmtData(S); } diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 07b4dea987ded..7ec4ecd41b2b7 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -21,15 +21,18 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Casting.h" +#include "llvm/ADT/StringRef.h" #include <cassert> #include <utility> +#include <string> namespace clang { -class LocationContext; class AnalysisContext; class FunctionDecl; - +class LocationContext; +class ProgramPointTag; + class ProgramPoint { public: enum Kind { BlockEdgeKind, @@ -42,7 +45,6 @@ public: PreStoreKind, PostStoreKind, PostPurgeDeadSymbolsKind, - PostStmtCustomKind, PostConditionKind, PostLValueKind, PostInitializerKind, @@ -58,25 +60,33 @@ private: // The LocationContext could be NULL to allow ProgramPoint to be used in // context insensitive analysis. const LocationContext *L; - const void *Tag; + const ProgramPointTag *Tag; + ProgramPoint(); + protected: - ProgramPoint(const void* P, Kind k, const LocationContext *l, - const void *tag = 0) + ProgramPoint(const void *P, Kind k, const LocationContext *l, + const ProgramPointTag *tag = 0) : Data(P, static_cast<const void*>(NULL)), K(k), L(l), Tag(tag) {} - ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l, - const void *tag = 0) + ProgramPoint(const void *P1, const void *P2, Kind k, const LocationContext *l, + const ProgramPointTag *tag = 0) : Data(P1, P2), K(k), L(l), Tag(tag) {} protected: - const void* getData1() const { return Data.first; } - const void* getData2() const { return Data.second; } + const void *getData1() const { return Data.first; } + const void *getData2() const { return Data.second; } public: + /// Create a new ProgramPoint object that is the same as the original + /// except for using the specified tag value. + ProgramPoint withTag(const ProgramPointTag *tag) const { + return ProgramPoint(Data.first, Data.second, K, L, tag); + } + Kind getKind() const { return K; } - const void *getTag() const { return Tag; } + const ProgramPointTag *getTag() const { return Tag; } const LocationContext *getLocationContext() const { return L; } @@ -93,7 +103,7 @@ public: return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag; } - bool operator!=(const ProgramPoint& RHS) const { + bool operator!=(const ProgramPoint &RHS) const { return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag; } @@ -104,29 +114,30 @@ public: ID.AddPointer(L); ID.AddPointer(Tag); } + + static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, + const LocationContext *LC, + const ProgramPointTag *tag); + }; class BlockEntrance : public ProgramPoint { public: - BlockEntrance(const CFGBlock* B, const LocationContext *L, - const void *tag = 0) - : ProgramPoint(B, BlockEntranceKind, L, tag) {} + BlockEntrance(const CFGBlock *B, const LocationContext *L, + const ProgramPointTag *tag = 0) + : ProgramPoint(B, BlockEntranceKind, L, tag) { + assert(B && "BlockEntrance requires non-null block"); + } - const CFGBlock* getBlock() const { + const CFGBlock *getBlock() const { return reinterpret_cast<const CFGBlock*>(getData1()); } const CFGElement getFirstElement() const { - const CFGBlock* B = getBlock(); + const CFGBlock *B = getBlock(); return B->empty() ? CFGElement() : B->front(); } - /// Create a new BlockEntrance object that is the same as the original - /// except for using the specified tag value. - BlockEntrance withTag(const void *tag) { - return BlockEntrance(getBlock(), getLocationContext(), tag); - } - static bool classof(const ProgramPoint* Location) { return Location->getKind() == BlockEntranceKind; } @@ -134,14 +145,14 @@ public: class BlockExit : public ProgramPoint { public: - BlockExit(const CFGBlock* B, const LocationContext *L) + BlockExit(const CFGBlock *B, const LocationContext *L) : ProgramPoint(B, BlockExitKind, L) {} - const CFGBlock* getBlock() const { + const CFGBlock *getBlock() const { return reinterpret_cast<const CFGBlock*>(getData1()); } - const Stmt* getTerminator() const { + const Stmt *getTerminator() const { return getBlock()->getTerminator(); } @@ -153,7 +164,7 @@ public: class StmtPoint : public ProgramPoint { public: StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, - const void *tag) + const ProgramPointTag *tag) : ProgramPoint(S, p2, k, L, tag) {} const Stmt *getStmt() const { return (const Stmt*) getData1(); } @@ -170,7 +181,7 @@ public: class PreStmt : public StmtPoint { public: - PreStmt(const Stmt *S, const LocationContext *L, const void *tag, + PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, const Stmt *SubStmt = 0) : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} @@ -183,16 +194,17 @@ public: class PostStmt : public StmtPoint { protected: - PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L, - const void *tag =0) + PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, + const ProgramPointTag *tag =0) : StmtPoint(S, data, k, L, tag) {} public: - explicit PostStmt(const Stmt* S, Kind k, - const LocationContext *L, const void *tag = 0) + explicit PostStmt(const Stmt *S, Kind k, + const LocationContext *L, const ProgramPointTag *tag = 0) : StmtPoint(S, NULL, k, L, tag) {} - explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0) + explicit PostStmt(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : StmtPoint(S, NULL, PostStmtKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -201,31 +213,11 @@ public: } }; -class PostStmtCustom : public PostStmt { -public: - PostStmtCustom(const Stmt* S, - const std::pair<const void*, const void*>* TaggedData,\ - const LocationContext *L) - : PostStmt(S, TaggedData, PostStmtCustomKind, L) {} - - const std::pair<const void*, const void*>& getTaggedPair() const { - return - *reinterpret_cast<const std::pair<const void*, const void*>*>(getData2()); - } - - const void* getTag() const { return getTaggedPair().first; } - - const void* getTaggedData() const { return getTaggedPair().second; } - - static bool classof(const ProgramPoint* Location) { - return Location->getKind() == PostStmtCustomKind; - } -}; - // PostCondition represents the post program point of a branch condition. class PostCondition : public PostStmt { public: - PostCondition(const Stmt* S, const LocationContext *L, const void *tag = 0) + PostCondition(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostConditionKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -236,7 +228,7 @@ public: class LocationCheck : public StmtPoint { protected: LocationCheck(const Stmt *S, const LocationContext *L, - ProgramPoint::Kind K, const void *tag) + ProgramPoint::Kind K, const ProgramPointTag *tag) : StmtPoint(S, NULL, K, L, tag) {} static bool classof(const ProgramPoint *location) { @@ -247,7 +239,8 @@ protected: class PreLoad : public LocationCheck { public: - PreLoad(const Stmt *S, const LocationContext *L, const void *tag = 0) + PreLoad(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : LocationCheck(S, L, PreLoadKind, tag) {} static bool classof(const ProgramPoint *location) { @@ -257,7 +250,8 @@ public: class PreStore : public LocationCheck { public: - PreStore(const Stmt *S, const LocationContext *L, const void *tag = 0) + PreStore(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : LocationCheck(S, L, PreStoreKind, tag) {} static bool classof(const ProgramPoint *location) { @@ -267,7 +261,8 @@ public: class PostLoad : public PostStmt { public: - PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0) + PostLoad(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostLoadKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -277,7 +272,8 @@ public: class PostStore : public PostStmt { public: - PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0) + PostStore(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostStoreKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -287,7 +283,8 @@ public: class PostLValue : public PostStmt { public: - PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0) + PostLValue(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostLValueKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -297,8 +294,8 @@ public: class PostPurgeDeadSymbols : public PostStmt { public: - PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L, - const void *tag = 0) + PostPurgeDeadSymbols(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) : PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {} static bool classof(const ProgramPoint* Location) { @@ -308,14 +305,17 @@ public: class BlockEdge : public ProgramPoint { public: - BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L) - : ProgramPoint(B1, B2, BlockEdgeKind, L) {} + BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) + : ProgramPoint(B1, B2, BlockEdgeKind, L) { + assert(B1 && "BlockEdge: source block must be non-null"); + assert(B2 && "BlockEdge: destination block must be non-null"); + } - const CFGBlock* getSrc() const { + const CFGBlock *getSrc() const { return static_cast<const CFGBlock*>(getData1()); } - const CFGBlock* getDst() const { + const CFGBlock *getDst() const { return static_cast<const CFGBlock*>(getData2()); } @@ -365,6 +365,29 @@ public: } }; +/// ProgramPoints can be "tagged" as representing points specific to a given +/// analysis entity. Tags are abstract annotations, with an associated +/// description and potentially other information. +class ProgramPointTag { +public: + ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {} + virtual ~ProgramPointTag(); + virtual StringRef getTagDescription() const = 0; + +protected: + /// Used to implement 'classof' in subclasses. + const void *getTagKind() { return TagKind; } + +private: + const void *TagKind; +}; + +class SimpleProgramPointTag : public ProgramPointTag { + std::string desc; +public: + SimpleProgramPointTag(StringRef description); + StringRef getTagDescription() const; +}; } // end namespace clang @@ -385,12 +408,12 @@ static inline clang::ProgramPoint getTombstoneKey() { return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); } -static unsigned getHashValue(const clang::ProgramPoint& Loc) { +static unsigned getHashValue(const clang::ProgramPoint &Loc) { return Loc.getHashValue(); } -static bool isEqual(const clang::ProgramPoint& L, - const clang::ProgramPoint& R) { +static bool isEqual(const clang::ProgramPoint &L, + const clang::ProgramPoint &R) { return L == R; } diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h index 27ecc66e66e3b..d25b84833c54d 100644 --- a/include/clang/Analysis/Support/BlkExprDeclBitVector.h +++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h @@ -62,16 +62,16 @@ struct DeclBitVector_Types { AnalysisDataTy() : NDecls(0) {} virtual ~AnalysisDataTy() {} - bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); } + bool isTracked(const NamedDecl *SD) { return DMap.find(SD) != DMap.end(); } - Idx getIdx(const NamedDecl* SD) const { + Idx getIdx(const NamedDecl *SD) const { DMapTy::const_iterator I = DMap.find(SD); return I == DMap.end() ? Idx() : Idx(I->second); } unsigned getNumDecls() const { return NDecls; } - void Register(const NamedDecl* SD) { + void Register(const NamedDecl *SD) { if (!isTracked(SD)) DMap[SD] = NDecls++; } @@ -117,11 +117,11 @@ struct DeclBitVector_Types { } llvm::BitVector::reference - operator()(const NamedDecl* ND, const AnalysisDataTy& AD) { + operator()(const NamedDecl *ND, const AnalysisDataTy& AD) { return getBit(AD.getIdx(ND)); } - bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const { + bool operator()(const NamedDecl *ND, const AnalysisDataTy& AD) const { return getBit(AD.getIdx(ND)); } @@ -171,14 +171,14 @@ struct StmtDeclBitVector_Types { //===--------------------------------------------------------------------===// class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy { - ASTContext* ctx; + ASTContext *ctx; CFG* cfg; public: AnalysisDataTy() : ctx(0), cfg(0) {} virtual ~AnalysisDataTy() {} - void setContext(ASTContext& c) { ctx = &c; } - ASTContext& getContext() { + void setContext(ASTContext &c) { ctx = &c; } + ASTContext &getContext() { assert(ctx && "ASTContext should not be NULL."); return *ctx; } @@ -186,10 +186,10 @@ struct StmtDeclBitVector_Types { void setCFG(CFG& c) { cfg = &c; } CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; } - bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); } + bool isTracked(const Stmt *S) { return cfg->isBlkExpr(S); } using DeclBitVector_Types::AnalysisDataTy::isTracked; - unsigned getIdx(const Stmt* S) const { + unsigned getIdx(const Stmt *S) const { CFG::BlkExprNumTy I = cfg->getBlkExprNum(S); assert(I && "Stmtession not tracked for bitvector."); return I; @@ -248,11 +248,11 @@ struct StmtDeclBitVector_Types { } llvm::BitVector::reference - operator()(const Stmt* S, const AnalysisDataTy& AD) { + operator()(const Stmt *S, const AnalysisDataTy& AD) { return BlkExprBV[AD.getIdx(S)]; } const llvm::BitVector::reference - operator()(const Stmt* S, const AnalysisDataTy& AD) const { + operator()(const Stmt *S, const AnalysisDataTy& AD) const { return const_cast<ValTy&>(*this)(S,AD); } diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index 95f4ace76e8c0..5c5ec2d7afd8f 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -28,8 +28,8 @@ static_cast<ImplClass*>(this)->Visit##CLASS##Decl( \ static_cast<CLASS##Decl*>(D)); \ break; -#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl* D) {} -#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl* D)\ +#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D) {} +#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D)\ { static_cast<ImplClass*>(this)->VisitVarDecl(D); } @@ -38,23 +38,23 @@ template <typename ImplClass> class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> { public: - void VisitDeclRefExpr(DeclRefExpr* DR) { + void VisitDeclRefExpr(DeclRefExpr *DR) { static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl()); } - void VisitDeclStmt(DeclStmt* DS) { + void VisitDeclStmt(DeclStmt *DS) { for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); DI != DE; ++DI) { - Decl* D = *DI; + Decl *D = *DI; static_cast<ImplClass*>(this)->VisitDecl(D); // Visit the initializer. - if (VarDecl* VD = dyn_cast<VarDecl>(D)) - if (Expr* I = VD->getInit()) + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + if (Expr *I = VD->getInit()) static_cast<ImplClass*>(this)->Visit(I); } } - void VisitDecl(Decl* D) { + void VisitDecl(Decl *D) { switch (D->getKind()) { DISPATCH_CASE(Function) DISPATCH_CASE(CXXMethod) @@ -69,7 +69,7 @@ public: DISPATCH_CASE(UsingDirective) DISPATCH_CASE(Using) default: - assert(false && "Subtype of ScopedDecl not handled."); + llvm_unreachable("Subtype of ScopedDecl not handled."); } } diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h index bb7cf0b97e534..4d1cabfc5c0b3 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -22,7 +22,7 @@ template <typename ImplClass> class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> { public: - void VisitStmt(Stmt* S) { + void VisitStmt(Stmt *S) { static_cast< ImplClass* >(this)->VisitChildren(S); } @@ -45,13 +45,13 @@ break; CONDVAR_CASE(WhileStmt) #undef CONDVAR_CASE default: - assert(false && "Infeasible"); + llvm_unreachable("Infeasible"); } static_cast<ImplClass*>(this)->Visit(CondVar->getInit()); } // Defining operator() allows the visitor to be used as a C++ style functor. - void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);} + void operator()(Stmt *S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);} }; } // end namespace clang diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h index 7fb4ab3ebad97..b354ba7b1680b 100644 --- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -33,7 +33,7 @@ static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); template <typename ImplClass, typename RetTy=void> class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { - Stmt* CurrentBlkStmt; + Stmt *CurrentBlkStmt; struct NullifyStmt { Stmt*& S; @@ -45,9 +45,9 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { public: CFGStmtVisitor() : CurrentBlkStmt(NULL) {} - Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; } + Stmt *getCurrentBlkStmt() const { return CurrentBlkStmt; } - RetTy Visit(Stmt* S) { + RetTy Visit(Stmt *S) { if (S == CurrentBlkStmt || !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S)) return StmtVisitor<ImplClass,RetTy>::Visit(S); @@ -67,7 +67,7 @@ public: /// the list of statements in a CFGBlock. For substatements, or when there /// is no implementation provided for a BlockStmt_XXX method, we default /// to using StmtVisitor's Visit method. - RetTy BlockStmt_Visit(Stmt* S) { + RetTy BlockStmt_Visit(Stmt *S) { CurrentBlkStmt = S; NullifyStmt cleanup(CurrentBlkStmt); @@ -106,23 +106,23 @@ public: DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator) - RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { + RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); } - RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt* S) { + RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt *S) { return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); } - RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) { + RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr *E) { return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E); } - RetTy BlockStmt_VisitExpr(Expr* E) { + RetTy BlockStmt_VisitExpr(Expr *E) { return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E); } - RetTy BlockStmt_VisitStmt(Stmt* S) { + RetTy BlockStmt_VisitStmt(Stmt *S) { return static_cast<ImplClass*>(this)->Visit(S); } @@ -141,14 +141,14 @@ public: //===--------------------------------------------------------------------===// /// VisitChildren: Call "Visit" on each child of S. - void VisitChildren(Stmt* S) { + void VisitChildren(Stmt *S) { switch (S->getStmtClass()) { default: break; case Stmt::StmtExprClass: { - CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt(); + CompoundStmt *CS = cast<StmtExpr>(S)->getSubStmt(); if (CS->body_empty()) return; static_cast<ImplClass*>(this)->Visit(CS->body_back()); return; |