diff options
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r-- | include/clang/Analysis/Analyses/Dominators.h | 212 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/FormatString.h | 140 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/LiveVariables.h | 10 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/PostOrderCFGView.h | 111 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/ReachableCode.h | 5 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/ThreadSafety.h | 14 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/UninitializedValues.h | 12 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisContext.h | 207 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Analysis/CFG.h | 188 | ||||
-rw-r--r-- | include/clang/Analysis/CallGraph.h | 257 | ||||
-rw-r--r-- | include/clang/Analysis/DomainSpecific/CocoaConventions.h | 12 | ||||
-rw-r--r-- | include/clang/Analysis/ProgramPoint.h | 113 | ||||
-rw-r--r-- | include/clang/Analysis/Support/SaveAndRestore.h | 47 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h | 3 |
15 files changed, 1066 insertions, 267 deletions
diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h new file mode 100644 index 0000000..e9a431a --- /dev/null +++ b/include/clang/Analysis/Analyses/Dominators.h @@ -0,0 +1,212 @@ +//==- Dominators.h - Implementation of dominators tree for Clang CFG C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the dominators tree functionality for Clang CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DOMINATORS_H +#define LLVM_CLANG_DOMINATORS_H + +#include "clang/Analysis/AnalysisContext.h" + +#include "llvm/Module.h" +#include "llvm/ADT/GraphTraits.h" +#include "clang/Analysis/CFG.h" +#include "llvm/Analysis/Dominators.h" +#include "llvm/Analysis/DominatorInternals.h" + +namespace clang { + +class CFGBlock; +typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode; + +/// \brief Concrete subclass of DominatorTreeBase for Clang +/// This class implements the dominators tree functionality given a Clang CFG. +/// +class DominatorTree : public ManagedAnalysis { + virtual void anchor(); +public: + llvm::DominatorTreeBase<CFGBlock>* DT; + + DominatorTree() { + DT = new llvm::DominatorTreeBase<CFGBlock>(false); + } + + ~DominatorTree() { + delete DT; + } + + llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; } + + /// \brief This method returns the root CFGBlock of the dominators tree. + /// + inline CFGBlock *getRoot() const { + return DT->getRoot(); + } + + /// \brief This method returns the root DomTreeNode, which is the wrapper + /// for CFGBlock. + inline DomTreeNode *getRootNode() const { + return DT->getRootNode(); + } + + /// \brief This method compares two dominator trees. + /// The method returns false if the other dominator tree matches this + /// dominator tree, otherwise returns true. + /// + inline bool compare(DominatorTree &Other) const { + DomTreeNode *R = getRootNode(); + DomTreeNode *OtherR = Other.getRootNode(); + + if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) + return true; + + if (DT->compare(Other.getBase())) + return true; + + return false; + } + + /// \brief This method builds the dominator tree for a given CFG + /// The CFG information is passed via AnalysisDeclContext + /// + void buildDominatorTree(AnalysisDeclContext &AC) { + cfg = AC.getCFG(); + DT->recalculate(*cfg); + } + + /// \brief This method dumps immediate dominators for each block, + /// mainly used for debug purposes. + /// + void dump() { + llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n"; + for (CFG::const_iterator I = cfg->begin(), + E = cfg->end(); I != E; ++I) { + if(DT->getNode(*I)->getIDom()) + llvm::errs() << "(" << (*I)->getBlockID() + << "," + << DT->getNode(*I)->getIDom()->getBlock()->getBlockID() + << ")\n"; + else llvm::errs() << "(" << (*I)->getBlockID() + << "," << (*I)->getBlockID() << ")\n"; + } + } + + /// \brief This method tests if one CFGBlock dominates the other. + /// The method return true if A dominates B, false otherwise. + /// Note a block always dominates itself. + /// + inline bool dominates(const CFGBlock* A, const CFGBlock* B) const { + return DT->dominates(A, B); + } + + /// \brief This method tests if one CFGBlock properly dominates the other. + /// The method return true if A properly dominates B, false otherwise. + /// + bool properlyDominates(const CFGBlock*A, const CFGBlock*B) const { + return DT->properlyDominates(A, B); + } + + /// \brief This method finds the nearest common dominator CFG block + /// for CFG block A and B. If there is no such block then return NULL. + /// + inline CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + + inline const CFGBlock *findNearestCommonDominator(const CFGBlock *A, + const CFGBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + + /// \brief This method is used to update the dominator + /// tree information when a node's immediate dominator changes. + /// + inline void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) { + DT->changeImmediateDominator(N, NewIDom); + } + + /// \brief This method tests if the given CFGBlock can be reachable from root. + /// Returns true if reachable, false otherwise. + /// + bool isReachableFromEntry(const CFGBlock *A) { + return DT->isReachableFromEntry(A); + } + + /// \brief This method releases the memory held by the dominator tree. + /// + virtual void releaseMemory() { + DT->releaseMemory(); + } + + /// \brief This method converts the dominator tree to human readable form. + /// + virtual void print(raw_ostream &OS, const llvm::Module* M= 0) const { + DT->print(OS); + } + +private: + CFG *cfg; +}; + +inline void WriteAsOperand(raw_ostream &OS, const CFGBlock *BB, + bool t) { + OS << "BB#" << BB->getBlockID(); +} + +} // end namespace clang + +//===------------------------------------- +/// DominatorTree GraphTraits specialization so the DominatorTree can be +/// iterable by generic graph iterators. +/// +namespace llvm { +template <> struct GraphTraits< ::clang::DomTreeNode* > { + typedef ::clang::DomTreeNode NodeType; + typedef NodeType::iterator ChildIteratorType; + + static NodeType *getEntryNode(NodeType *N) { + return N; + } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->end(); + } + + typedef df_iterator< ::clang::DomTreeNode* > nodes_iterator; + + static nodes_iterator nodes_begin(::clang::DomTreeNode *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(::clang::DomTreeNode *N) { + return df_end(getEntryNode(N)); + } +}; + +template <> struct GraphTraits< ::clang::DominatorTree* > + : public GraphTraits< ::clang::DomTreeNode* > { + static NodeType *getEntryNode(::clang::DominatorTree *DT) { + return DT->getRootNode(); + } + + static nodes_iterator nodes_begin(::clang::DominatorTree *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(::clang::DominatorTree *N) { + return df_end(getEntryNode(N)); + } +}; +} // end namespace llvm + +#endif diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 61f4164..9ec27ce 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -66,11 +66,14 @@ public: AsChar, // 'hh' AsShort, // 'h' AsLong, // 'l' - AsLongLong, // 'll', 'q' (BSD, deprecated) + AsLongLong, // 'll' + AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) AsIntMax, // 'j' AsSizeT, // 'z' AsPtrDiff, // 't' AsLongDouble, // 'L' + AsAllocate, // for '%as', GNU extension to C90 scanf + AsMAllocate, // for '%ms', GNU extension to scanf AsWideChar = AsLong // for '%ls', only makes sense for printf }; @@ -104,7 +107,7 @@ private: const char *Position; Kind kind; }; - + class ConversionSpecifier { public: enum Kind { @@ -113,14 +116,14 @@ public: cArg, dArg, iArg, - IntArgBeg = cArg, IntArgEnd = iArg, - + IntArgBeg = cArg, IntArgEnd = iArg, + oArg, uArg, xArg, XArg, UIntArgBeg = oArg, UIntArgEnd = XArg, - + fArg, FArg, eArg, @@ -130,44 +133,44 @@ public: aArg, AArg, DoubleArgBeg = fArg, DoubleArgEnd = AArg, - + sArg, pArg, nArg, PercentArg, CArg, SArg, - + // ** Printf-specific ** - + // Objective-C specific specifiers. ObjCObjArg, // '@' ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, - + // GlibC specific specifiers. PrintErrno, // 'm' - + PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno, - - // ** Scanf-specific ** + + // ** Scanf-specific ** ScanListArg, // '[' ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg }; - + ConversionSpecifier(bool isPrintf) : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {} - + ConversionSpecifier(bool isPrintf, const char *pos, Kind k) : IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {} - + const char *getStart() const { return Position; } - + StringRef getCharacters() const { return StringRef(getStart(), getLength()); } - + bool consumesDataArgument() const { switch (kind) { case PrintErrno: @@ -178,15 +181,16 @@ public: return true; } } - + Kind getKind() const { return kind; } void setKind(Kind k) { kind = k; } unsigned getLength() const { return EndScanList ? EndScanList - Position : 1; } - + + bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } const char *toString() const; - + bool isPrintfKind() const { return IsPrintf; } protected: @@ -199,15 +203,18 @@ protected: class ArgTypeResult { public: enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, - CStrTy, WCStrTy, WIntTy }; + AnyCharTy, CStrTy, WCStrTy, WIntTy }; private: const Kind K; QualType T; - ArgTypeResult(bool) : K(InvalidTy) {} + const char *Name; + ArgTypeResult(bool) : K(InvalidTy), Name(0) {} public: - ArgTypeResult(Kind k = UnknownTy) : K(k) {} - ArgTypeResult(QualType t) : K(SpecificTy), T(t) {} - ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {} + 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); } @@ -222,6 +229,8 @@ public: bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; } QualType getRepresentativeType(ASTContext &C) const; + + std::string getRepresentativeTypeName(ASTContext &C) const; }; class OptionalAmount { @@ -297,9 +306,9 @@ protected: LengthModifier LM; OptionalAmount FieldWidth; ConversionSpecifier CS; - /// Positional arguments, an IEEE extension: - /// IEEE Std 1003.1, 2004 Edition - /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html + /// Positional arguments, an IEEE extension: + /// IEEE Std 1003.1, 2004 Edition + /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html bool UsesPositionalArg; unsigned argIndex; public: @@ -337,8 +346,14 @@ public: } bool usesPositionalArg() const { return UsesPositionalArg; } - + bool hasValidLengthModifier() const; + + bool hasStandardLengthModifier() const; + + bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; + + bool hasStandardLengthConversionCombination() const; }; } // end analyze_format_string namespace @@ -348,7 +363,7 @@ public: namespace analyze_printf { -class PrintfConversionSpecifier : +class PrintfConversionSpecifier : public analyze_format_string::ConversionSpecifier { public: PrintfConversionSpecifier() @@ -359,9 +374,8 @@ public: bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; } - bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } - bool isDoubleArg() const { return kind >= DoubleArgBeg && - kind <= DoubleArgBeg; } + bool isDoubleArg() const { return kind >= DoubleArgBeg && + kind <= DoubleArgEnd; } unsigned getLength() const { // Conversion specifiers currently only are represented by // single characters, but we be flexible. @@ -438,7 +452,7 @@ public: const OptionalAmount &getPrecision() const { return Precision; } - + bool consumesDataArgument() const { return getConversionSpecifier().consumesDataArgument(); } @@ -448,9 +462,9 @@ 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) const; + ArgTypeResult getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; - const OptionalFlag &hasThousandsGrouping() const { + const OptionalFlag &hasThousandsGrouping() const { return HasThousandsGrouping; } const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } @@ -460,14 +474,15 @@ public: const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } bool usesPositionalArg() const { return UsesPositionalArg; } - /// Changes the specifier and length according to a QualType, retaining any - /// flags or options. Returns true on success, or false when a conversion - /// was not successful. - bool fixType(QualType QT); + /// Changes the specifier and length according to a QualType, retaining any + /// flags or options. Returns true on success, or false when a conversion + /// was not successful. + bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, + bool IsObjCLiteral); void toString(raw_ostream &os) const; - // Validation methods - to check if any element results in undefined behavior + // Validation methods - to check if any element results in undefined behavior bool hasValidPlusPrefix() const; bool hasValidAlternativeForm() const; bool hasValidLeadingZeros() const; @@ -495,16 +510,41 @@ public: : ConversionSpecifier(false, pos, k) {} void setEndScanList(const char *pos) { EndScanList = pos; } - + static bool classof(const analyze_format_string::ConversionSpecifier *CS) { return !CS->isPrintfKind(); - } + } }; +using analyze_format_string::ArgTypeResult; 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: @@ -528,11 +568,17 @@ public: const ScanfConversionSpecifier &getConversionSpecifier() const { return cast<ScanfConversionSpecifier>(CS); } - + bool consumesDataArgument() const { return CS.consumesDataArgument() && !SuppressAssignment; } + ScanfArgTypeResult getArgType(ASTContext &Ctx) const; + + bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx); + + void toString(raw_ostream &os) const; + static ScanfSpecifier Parse(const char *beg, const char *end); }; @@ -552,6 +598,8 @@ public: virtual void HandleNullChar(const char *nullCharacter) {} + virtual void HandlePosition(const char *startPos, unsigned posLen) {} + virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, PositionContext p) {} @@ -594,10 +642,10 @@ public: }; bool ParsePrintfString(FormatStringHandler &H, - const char *beg, const char *end); + const char *beg, const char *end, const LangOptions &LO); bool ParseScanfString(FormatStringHandler &H, - const char *beg, const char *end); + const char *beg, const char *end, const LangOptions &LO); } // end analyze_format_string namespace } // end clang namespace diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 302ae1c..c9f39b4 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -52,7 +52,9 @@ public: friend class LiveVariables; }; - struct Observer { + class Observer { + virtual void anchor(); + public: virtual ~Observer() {} /// A callback invoked right before invoking the @@ -70,7 +72,7 @@ public: virtual ~LiveVariables(); /// Compute the liveness information for a given CFG. - static LiveVariables *computeLiveness(AnalysisContext &analysisContext, + static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext, bool killAtAssign); /// Return true if a variable is live at the end of a @@ -93,7 +95,7 @@ public: void runOnAllBlocks(Observer &obs); - static LiveVariables *create(AnalysisContext &analysisContext) { + static LiveVariables *create(AnalysisDeclContext &analysisContext) { return computeLiveness(analysisContext, true); } @@ -106,7 +108,7 @@ private: class RelaxedLiveVariables : public LiveVariables { public: - static LiveVariables *create(AnalysisContext &analysisContext) { + static LiveVariables *create(AnalysisDeclContext &analysisContext) { return computeLiveness(analysisContext, false); } diff --git a/include/clang/Analysis/Analyses/PostOrderCFGView.h b/include/clang/Analysis/Analyses/PostOrderCFGView.h new file mode 100644 index 0000000..4e3244e --- /dev/null +++ b/include/clang/Analysis/Analyses/PostOrderCFGView.h @@ -0,0 +1,111 @@ +//===- PostOrderCFGView.h - Post order view of CFG blocks ---------*- C++ --*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements post order view of the blocks in a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_POSTORDER_CFGVIEW +#define LLVM_CLANG_POSTORDER_CFGVIEW + +#include <vector> +//#include <algorithm> + +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/BitVector.h" + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" + +namespace clang { + +class PostOrderCFGView : public ManagedAnalysis { + virtual void anchor(); +public: + /// \brief Implements a set of CFGBlocks using a BitVector. + /// + /// This class contains a minimal interface, primarily dictated by the SetType + /// template parameter of the llvm::po_iterator template, as used with + /// external storage. We also use this set to keep track of which CFGBlocks we + /// visit during the analysis. + class CFGBlockSet { + llvm::BitVector VisitedBlockIDs; + public: + // po_iterator requires this iterator, but the only interface needed is the + // value_type typedef. + struct iterator { typedef const CFGBlock *value_type; }; + + CFGBlockSet() {} + CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {} + + /// \brief Set the bit associated with a particular CFGBlock. + /// This is the important method for the SetType template parameter. + bool insert(const CFGBlock *Block) { + // Note that insert() is called by po_iterator, which doesn't check to + // make sure that Block is non-null. Moreover, the CFGBlock iterator will + // occasionally hand out null pointers for pruned edges, so we catch those + // here. + if (Block == 0) + return false; // if an edge is trivially false. + if (VisitedBlockIDs.test(Block->getBlockID())) + return false; + VisitedBlockIDs.set(Block->getBlockID()); + return true; + } + + /// \brief Check if the bit for a CFGBlock has been already set. + /// This method is for tracking visited blocks in the main threadsafety + /// loop. Block must not be null. + bool alreadySet(const CFGBlock *Block) { + return VisitedBlockIDs.test(Block->getBlockID()); + } + }; + +private: + typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator; + std::vector<const CFGBlock*> Blocks; + + typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy; + BlockOrderTy BlockOrder; + +public: + typedef std::vector<const CFGBlock*>::reverse_iterator iterator; + + PostOrderCFGView(const CFG *cfg); + + iterator begin() { return Blocks.rbegin(); } + iterator end() { return Blocks.rend(); } + + bool empty() { return begin() == end(); } + + struct BlockOrderCompare; + friend struct BlockOrderCompare; + + struct BlockOrderCompare { + const PostOrderCFGView &POV; + public: + BlockOrderCompare(const PostOrderCFGView &pov) : POV(pov) {} + bool operator()(const CFGBlock *b1, const CFGBlock *b2) const; + }; + + BlockOrderCompare getComparator() const { + return BlockOrderCompare(*this); + } + + // Used by AnalyisContext to construct this object. + static const void *getTag(); + + static PostOrderCFGView *create(AnalysisDeclContext &analysisContext); +}; + +} // end clang namespace + +#endif + diff --git a/include/clang/Analysis/Analyses/ReachableCode.h b/include/clang/Analysis/Analyses/ReachableCode.h index 6cf7fa4..30c5b2d 100644 --- a/include/clang/Analysis/Analyses/ReachableCode.h +++ b/include/clang/Analysis/Analyses/ReachableCode.h @@ -25,7 +25,7 @@ namespace llvm { } namespace clang { - class AnalysisContext; + class AnalysisDeclContext; class CFGBlock; } @@ -37,6 +37,7 @@ namespace clang { namespace reachable_code { class Callback { + virtual void anchor(); public: virtual ~Callback() {} virtual void HandleUnreachable(SourceLocation L, SourceRange R1, @@ -48,7 +49,7 @@ public: unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable); -void FindUnreachableCode(AnalysisContext &AC, Callback &CB); +void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB); }} // end namespace clang::reachable_code diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h index a325056..26e258d 100644 --- a/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/include/clang/Analysis/Analyses/ThreadSafety.h @@ -67,7 +67,7 @@ enum LockErrorKind { class ThreadSafetyHandler { public: typedef llvm::StringRef Name; - virtual ~ThreadSafetyHandler() = 0; + virtual ~ThreadSafetyHandler(); /// Warn about lock expressions which fail to resolve to lockable objects. /// \param Loc -- the SourceLocation of the unresolved expression. @@ -93,9 +93,14 @@ public: /// 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 LocLocked -- The location of the lock expression where the mutex is + /// locked + /// \param LocEndOfScope -- The location of the end of the scope where the + /// mutex is no longer held /// \param LEK -- which of the three above cases we should warn for - virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc, + virtual void handleMutexHeldEndOfScope(Name LockName, + SourceLocation LocLocked, + SourceLocation LocEndOfScope, LockErrorKind LEK){} /// Warn when a mutex is held exclusively and shared at the same point. For @@ -143,7 +148,8 @@ public: /// 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); +void runThreadSafetyAnalysis(AnalysisDeclContext &AC, + ThreadSafetyHandler &Handler); /// \brief Helper function that returns a LockKind required for the given level /// of access. diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index e2e4f35..4ee6698 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -1,4 +1,4 @@ -//= UninitializedValues.h - Finding uses of uninitialized values --*- C++ -*-==// +//= UninitializedValues.h - Finding uses of uninitialized values -*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -17,12 +17,12 @@ namespace clang { -class AnalysisContext; -class CFG; +class AnalysisDeclContext; +class CFG; class DeclContext; class Expr; class VarDecl; - + class UninitVariablesHandler { public: UninitVariablesHandler() {} @@ -32,7 +32,7 @@ public: 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. @@ -45,7 +45,7 @@ struct UninitVariablesAnalysisStats { }; void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, - AnalysisContext &ac, + AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats); diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 3d0e88a..6b6f8ef 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file defines AnalysisContext, a class that manages the analysis context -// data for path sensitive analysis. +// This file defines AnalysisDeclContext, a class that manages the analysis +// context data for path sensitive analysis. // //===----------------------------------------------------------------------===// @@ -38,17 +38,19 @@ class PseudoConstantAnalysis; class ImplicitParamDecl; class LocationContextManager; class StackFrameContext; - +class AnalysisDeclContextManager; +class LocationContext; + namespace idx { class TranslationUnit; } /// The base class of a hierarchy of objects representing analyses tied -/// to AnalysisContext. +/// to AnalysisDeclContext. class ManagedAnalysis { protected: ManagedAnalysis() {} public: virtual ~ManagedAnalysis(); - + // Subclasses need to implement: // // static const void *getTag(); @@ -56,47 +58,55 @@ public: // Which returns a fixed pointer address to distinguish classes of // analysis objects. They also need to implement: // - // static [Derived*] create(AnalysisContext &Ctx); + // static [Derived*] create(AnalysisDeclContext &Ctx); // - // which creates the analysis object given an AnalysisContext. + // which creates the analysis object given an AnalysisDeclContext. }; - -/// AnalysisContext contains the context data for the function or method under -/// analysis. -class AnalysisContext { + + +/// AnalysisDeclContext contains the context data for the function or method +/// under analysis. +class AnalysisDeclContext { + /// Backpoint to the AnalysisManager object that created this + /// AnalysisDeclContext. This may be null. + AnalysisDeclContextManager *Manager; + const Decl *D; // TranslationUnit is NULL if we don't have multiple translation units. idx::TranslationUnit *TU; - llvm::OwningPtr<CFG> cfg, completeCFG; - llvm::OwningPtr<CFGStmtMap> cfgStmtMap; + OwningPtr<CFG> cfg, completeCFG; + OwningPtr<CFGStmtMap> cfgStmtMap; CFG::BuildOptions cfgBuildOptions; CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs; - + bool builtCFG, builtCompleteCFG; - llvm::OwningPtr<LiveVariables> liveness; - llvm::OwningPtr<LiveVariables> relaxedLiveness; - llvm::OwningPtr<ParentMap> PM; - llvm::OwningPtr<PseudoConstantAnalysis> PCA; - llvm::OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA; + OwningPtr<LiveVariables> liveness; + OwningPtr<LiveVariables> relaxedLiveness; + OwningPtr<ParentMap> PM; + OwningPtr<PseudoConstantAnalysis> PCA; + OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA; llvm::BumpPtrAllocator A; - // FIXME: remove. llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars; void *ManagedAnalyses; public: - AnalysisContext(const Decl *d, idx::TranslationUnit *tu); + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, + const Decl *D, + idx::TranslationUnit *TU); - AnalysisContext(const Decl *d, idx::TranslationUnit *tu, - const CFG::BuildOptions &buildOptions); + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, + const Decl *D, + idx::TranslationUnit *TU, + const CFG::BuildOptions &BuildOptions); - ~AnalysisContext(); + ~AnalysisDeclContext(); ASTContext &getASTContext() { return D->getASTContext(); } const Decl *getDecl() const { return D; } @@ -111,12 +121,12 @@ public: 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 getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; } bool getUseUnoptimizedCFG() const { return !cfgBuildOptions.PruneTriviallyFalseEdges; } @@ -125,18 +135,18 @@ public: void registerForcedBlockExpression(const Stmt *stmt); const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); - + Stmt *getBody() const; CFG *getCFG(); - + CFGStmtMap *getCFGStmtMap(); CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis(); - + /// Return a version of the CFG without any edges pruned. CFG *getUnoptimizedCFG(); - void dumpCFG(); + void dumpCFG(bool ShowColors); /// \brief Returns true if we have built a CFG for this analysis context. /// Note that this doesn't correspond to whether or not a valid CFG exists, it @@ -152,9 +162,14 @@ public: getReferencedBlockVars(const BlockDecl *BD); /// Return the ImplicitParamDecl* associated with 'self' if this - /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. + /// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise. const ImplicitParamDecl *getSelfDecl() const; - + + const StackFrameContext *getStackFrame(LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx); + /// Return the specified analysis object, lazily running the analysis if /// necessary. Return NULL if the analysis could not run. template <typename T> @@ -168,31 +183,8 @@ public: } private: ManagedAnalysis *&getAnalysisImpl(const void* tag); -}; - -class AnalysisContextManager { - typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap; - ContextMap Contexts; - CFG::BuildOptions cfgBuildOptions; -public: - AnalysisContextManager(bool useUnoptimizedCFG = false, - bool addImplicitDtors = false, - bool addInitializers = false); - - ~AnalysisContextManager(); - AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0); - - bool getUseUnoptimizedCFG() const { - return !cfgBuildOptions.PruneTriviallyFalseEdges; - } - - CFG::BuildOptions &getCFGBuildOptions() { - return cfgBuildOptions; - } - - /// Discard all previously created AnalysisContexts. - void clear(); + LocationContextManager &getLocationContextManager(); }; class LocationContext : public llvm::FoldingSetNode { @@ -202,13 +194,14 @@ public: private: ContextKind Kind; - // AnalysisContext can't be const since some methods may modify its member. - AnalysisContext *Ctx; + // AnalysisDeclContext can't be const since some methods may modify its + // member. + AnalysisDeclContext *Ctx; const LocationContext *Parent; protected: - LocationContext(ContextKind k, AnalysisContext *ctx, + LocationContext(ContextKind k, AnalysisDeclContext *ctx, const LocationContext *parent) : Kind(k), Ctx(ctx), Parent(parent) {} @@ -217,27 +210,27 @@ public: ContextKind getKind() const { return Kind; } - AnalysisContext *getAnalysisContext() const { return Ctx; } + AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } - idx::TranslationUnit *getTranslationUnit() const { - return Ctx->getTranslationUnit(); + idx::TranslationUnit *getTranslationUnit() const { + return Ctx->getTranslationUnit(); } const LocationContext *getParent() const { return Parent; } bool isParentOf(const LocationContext *LC) const; - const Decl *getDecl() const { return getAnalysisContext()->getDecl(); } + const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); } - CFG *getCFG() const { return getAnalysisContext()->getCFG(); } + CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); } template <typename T> T *getAnalysis() const { - return getAnalysisContext()->getAnalysis<T>(); + return getAnalysisDeclContext()->getAnalysis<T>(); } ParentMap &getParentMap() const { - return getAnalysisContext()->getParentMap(); + return getAnalysisDeclContext()->getParentMap(); } const ImplicitParamDecl *getSelfDecl() const { @@ -255,7 +248,7 @@ public: public: static void ProfileCommon(llvm::FoldingSetNodeID &ID, ContextKind ck, - AnalysisContext *ctx, + AnalysisDeclContext *ctx, const LocationContext *parent, const void *data); }; @@ -271,8 +264,8 @@ class StackFrameContext : public LocationContext { unsigned Index; friend class LocationContextManager; - StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, + StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent, + const Stmt *s, const CFGBlock *blk, unsigned idx) : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk), Index(idx) {} @@ -288,7 +281,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s, const CFGBlock *blk, unsigned idx) { ProfileCommon(ID, StackFrame, ctx, parent, s); @@ -305,7 +298,7 @@ class ScopeContext : public LocationContext { const Stmt *Enter; friend class LocationContextManager; - ScopeContext(AnalysisContext *ctx, const LocationContext *parent, + ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s) : LocationContext(Scope, ctx, parent), Enter(s) {} @@ -314,7 +307,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s) { ProfileCommon(ID, Scope, ctx, parent, s); } @@ -331,7 +324,8 @@ class BlockInvocationContext : public LocationContext { friend class LocationContextManager; - BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent, + BlockInvocationContext(AnalysisDeclContext *ctx, + const LocationContext *parent, const BlockDecl *bd) : LocationContext(Block, ctx, parent), BD(bd) {} @@ -342,7 +336,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, const LocationContext *parent, const BlockDecl *bd) { ProfileCommon(ID, Block, ctx, parent, bd); } @@ -357,12 +351,12 @@ class LocationContextManager { public: ~LocationContextManager(); - const StackFrameContext *getStackFrame(AnalysisContext *ctx, + const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s, const CFGBlock *blk, unsigned idx); - const ScopeContext *getScope(AnalysisContext *ctx, + const ScopeContext *getScope(AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s); @@ -370,10 +364,69 @@ public: void clear(); private: template <typename LOC, typename DATA> - const LOC *getLocationContext(AnalysisContext *ctx, + const LOC *getLocationContext(AnalysisDeclContext *ctx, const LocationContext *parent, const DATA *d); }; +class AnalysisDeclContextManager { + typedef llvm::DenseMap<const Decl*, AnalysisDeclContext*> ContextMap; + + ContextMap Contexts; + LocationContextManager LocContexts; + CFG::BuildOptions cfgBuildOptions; + +public: + AnalysisDeclContextManager(bool useUnoptimizedCFG = false, + bool addImplicitDtors = false, + bool addInitializers = false); + + ~AnalysisDeclContextManager(); + + AnalysisDeclContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0); + + bool getUseUnoptimizedCFG() const { + return !cfgBuildOptions.PruneTriviallyFalseEdges; + } + + CFG::BuildOptions &getCFGBuildOptions() { + return cfgBuildOptions; + } + + const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx, + LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx) { + return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx); + } + + // 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); + } + + // Get a stack frame with parent. + StackFrameContext const *getStackFrame(const Decl *D, + LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx) { + return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx); + } + + + /// Discard all previously created AnalysisDeclContexts. + void clear(); + +private: + friend class AnalysisDeclContext; + + LocationContextManager &getLocationContextManager() { + return LocContexts; + } +}; + } // end clang namespace #endif diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index 16d31b4..d4e1f5f 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,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM, + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) 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 f191c80..27b22b8 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -67,22 +67,22 @@ protected: CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = 0) : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3), - Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {} + Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {} public: CFGElement() {} - Kind getKind() const { + Kind getKind() const { unsigned x = Data2.getInt(); x <<= 2; x |= Data1.getInt(); return (Kind) x; } - + bool isValid() const { return getKind() != Invalid; } operator bool() const { return isValid(); } - + template<class ElemTy> const ElemTy *getAs() const { if (llvm::isa<ElemTy>(this)) return static_cast<const ElemTy*>(this); @@ -96,7 +96,7 @@ class CFGStmt : public CFGElement { public: CFGStmt(Stmt *S) : CFGElement(Statement, S) {} - const Stmt *getStmt() const { + const Stmt *getStmt() const { return static_cast<const Stmt *>(Data1.getPointer()); } @@ -125,9 +125,9 @@ public: /// by compiler on various occasions. class CFGImplicitDtor : public CFGElement { protected: - CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0) + CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0) : CFGElement(kind, data1, data2) { - assert(kind >= DTOR_BEGIN && kind <= DTOR_END); + assert(kind >= DTOR_BEGIN && kind <= DTOR_END); } public: @@ -272,12 +272,12 @@ class CFGBlock { ImplTy Impl; public: ElementList(BumpVectorContext &C) : Impl(C, 4) {} - + typedef std::reverse_iterator<ImplTy::iterator> iterator; typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; typedef ImplTy::iterator reverse_iterator; - typedef ImplTy::const_iterator const_reverse_iterator; - + typedef ImplTy::const_iterator const_reverse_iterator; + 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) { @@ -286,7 +286,7 @@ class CFGBlock { CFGElement front() const { return Impl.back(); } CFGElement back() const { return Impl.front(); } - + iterator begin() { return Impl.rbegin(); } iterator end() { return Impl.rend(); } const_iterator begin() const { return Impl.rbegin(); } @@ -300,7 +300,7 @@ class CFGBlock { assert(i < Impl.size()); return Impl[Impl.size() - 1 - i]; } - + size_t size() const { return Impl.size(); } bool empty() const { return Impl.empty(); } }; @@ -344,10 +344,14 @@ class CFGBlock { /// storage if the memory usage of CFGBlock becomes an issue. unsigned HasNoReturnElement : 1; + /// Parent - The parent CFG that owns this CFGBlock. + CFG *Parent; + public: - explicit CFGBlock(unsigned blockid, BumpVectorContext &C) - : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), - BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false) {} + explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent) + : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), + BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false), + Parent(parent) {} ~CFGBlock() {} // Statement iterators @@ -489,16 +493,19 @@ public: unsigned getBlockID() const { return BlockID; } - void dump(const CFG *cfg, const LangOptions &LO) const; - void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const; + CFG *getParent() const { return Parent; } + + void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const; + void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO, + bool ShowColors) const; void printTerminator(raw_ostream &OS, const LangOptions &LO) const; - + 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) { Elements.push_back(CFGStmt(statement), C); } @@ -515,7 +522,7 @@ public: void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) { Elements.push_back(CFGMemberDtor(FD), C); } - + void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) { Elements.push_back(CFGTemporaryDtor(E), C); } @@ -554,22 +561,22 @@ public: llvm::BitVector alwaysAddMask; public: typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs; - ForcedBlkExprs **forcedBlkExprs; + ForcedBlkExprs **forcedBlkExprs; 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; @@ -583,6 +590,55 @@ public: ,AddImplicitDtors(false) {} }; + /// \brief Provides a custom implementation of the iterator class to have the + /// same interface as Function::iterator - iterator returns CFGBlock + /// (not a pointer to CFGBlock). + class graph_iterator { + public: + typedef const CFGBlock value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef BumpVector<CFGBlock*>::iterator ImplTy; + + graph_iterator(const ImplTy &i) : I(i) {} + + bool operator==(const graph_iterator &X) const { return I == X.I; } + bool operator!=(const graph_iterator &X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + operator CFGBlock* () { return *I; } + + graph_iterator &operator++() { ++I; return *this; } + graph_iterator &operator--() { --I; return *this; } + + private: + ImplTy I; + }; + + class const_graph_iterator { + public: + typedef const CFGBlock value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef BumpVector<CFGBlock*>::const_iterator ImplTy; + + const_graph_iterator(const ImplTy &i) : I(i) {} + + bool operator==(const const_graph_iterator &X) const { return I == X.I; } + bool operator!=(const const_graph_iterator &X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + operator CFGBlock* () const { return *I; } + + const_graph_iterator &operator++() { ++I; return *this; } + const_graph_iterator &operator--() { --I; return *this; } + + private: + ImplTy I; + }; + /// 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, @@ -605,7 +661,7 @@ public: // Block Iterators //===--------------------------------------------------------------------===// - typedef BumpVector<CFGBlock*> CFGBlockListTy; + typedef BumpVector<CFGBlock*> CFGBlockListTy; typedef CFGBlockListTy::iterator iterator; typedef CFGBlockListTy::const_iterator const_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; @@ -619,6 +675,15 @@ public: const_iterator begin() const { return Blocks.begin(); } const_iterator end() const { return Blocks.end(); } + graph_iterator nodes_begin() { return graph_iterator(Blocks.begin()); } + graph_iterator nodes_end() { return graph_iterator(Blocks.end()); } + const_graph_iterator nodes_begin() const { + return const_graph_iterator(Blocks.begin()); + } + const_graph_iterator nodes_end() const { + return const_graph_iterator(Blocks.end()); + } + reverse_iterator rbegin() { return Blocks.rbegin(); } reverse_iterator rend() { return Blocks.rend(); } const_reverse_iterator rbegin() const { return Blocks.rbegin(); } @@ -631,7 +696,7 @@ public: 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(); @@ -639,7 +704,7 @@ public: try_block_iterator try_blocks_end() const { return TryDispatchBlocks.end(); } - + void addTryDispatchBlock(const CFGBlock *block) { TryDispatchBlocks.push_back(block); } @@ -681,13 +746,18 @@ public: /// start at 0). unsigned getNumBlockIDs() const { return NumBlockIDs; } + /// size - Return the total number of CFGBlocks within the CFG + /// This is simply a renaming of the getNumBlockIDs(). This is necessary + /// because the dominator implementation needs such an interface. + unsigned size() const { return NumBlockIDs; } + //===--------------------------------------------------------------------===// // CFG Debugging: Pretty-Printing and Visualization. //===--------------------------------------------------------------------===// void viewCFG(const LangOptions &LO) const; - void print(raw_ostream &OS, const LangOptions &LO) const; - void dump(const LangOptions &LO) const; + void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const; + void dump(const LangOptions &LO, bool ShowColors) const; //===--------------------------------------------------------------------===// // Internal: constructors and data. @@ -701,7 +771,7 @@ public: llvm::BumpPtrAllocator& getAllocator() { return BlkBVC.getAllocator(); } - + BumpVectorContext &getBumpVectorContext() { return BlkBVC; } @@ -717,11 +787,11 @@ private: // 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; - + 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; @@ -781,6 +851,20 @@ template <> struct GraphTraits< const ::clang::CFGBlock *> { { return N->succ_end(); } }; +template <> struct GraphTraits<Inverse< ::clang::CFGBlock*> > { + typedef ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse< ::clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > { typedef const ::clang::CFGBlock NodeType; typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; @@ -800,37 +884,55 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > { template <> struct GraphTraits< ::clang::CFG* > : public GraphTraits< ::clang::CFGBlock *> { - typedef ::clang::CFG::iterator nodes_iterator; + typedef ::clang::CFG::graph_iterator nodes_iterator; - static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); } - static nodes_iterator nodes_begin(::clang::CFG* F) { return F->begin(); } - static nodes_iterator nodes_end(::clang::CFG* F) { return F->end(); } + static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();} + static nodes_iterator nodes_end(::clang::CFG* F) { return F->nodes_end(); } + static unsigned size(::clang::CFG* F) { return F->size(); } }; template <> struct GraphTraits<const ::clang::CFG* > : public GraphTraits<const ::clang::CFGBlock *> { - typedef ::clang::CFG::const_iterator nodes_iterator; + typedef ::clang::CFG::const_graph_iterator nodes_iterator; static NodeType *getEntryNode( const ::clang::CFG* F) { return &F->getEntry(); } static nodes_iterator nodes_begin( const ::clang::CFG* F) { - return F->begin(); + return F->nodes_begin(); } static nodes_iterator nodes_end( const ::clang::CFG* F) { - return F->end(); + return F->nodes_end(); + } + static unsigned size(const ::clang::CFG* F) { + return F->size(); } }; +template <> struct GraphTraits<Inverse< ::clang::CFG*> > + : public GraphTraits<Inverse< ::clang::CFGBlock*> > { + + typedef ::clang::CFG::graph_iterator nodes_iterator; + + static NodeType *getEntryNode( ::clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();} + static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); } +}; + template <> struct GraphTraits<Inverse<const ::clang::CFG*> > : public GraphTraits<Inverse<const ::clang::CFGBlock*> > { - typedef ::clang::CFG::const_iterator nodes_iterator; + typedef ::clang::CFG::const_graph_iterator nodes_iterator; static NodeType *getEntryNode(const ::clang::CFG* F) { return &F->getExit(); } - static nodes_iterator nodes_begin(const ::clang::CFG* F) { return F->begin();} - static nodes_iterator nodes_end(const ::clang::CFG* F) { return F->end(); } + static nodes_iterator nodes_begin(const ::clang::CFG* F) { + return F->nodes_begin(); + } + static nodes_iterator nodes_end(const ::clang::CFG* F) { + return F->nodes_end(); + } }; } // end llvm namespace #endif diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h new file mode 100644 index 0000000..9b68073 --- /dev/null +++ b/include/clang/Analysis/CallGraph.h @@ -0,0 +1,257 @@ +//== CallGraph.h - AST-based Call graph ------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the AST-based CallGraph. +// +// A call graph for functions whose definitions/bodies are available in the +// current translation unit. The graph has a "virtual" root node that contains +// edges to all externally available functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH +#define LLVM_CLANG_ANALYSIS_CALLGRAPH + +#include "clang/AST/DeclBase.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +class CallGraphNode; + +/// \class 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 +/// declarations. +class CallGraph : public RecursiveASTVisitor<CallGraph> { + friend class CallGraphNode; + + typedef llvm::DenseMap<const Decl *, CallGraphNode *> FunctionMapTy; + + /// FunctionMap owns all CallGraphNodes. + FunctionMapTy FunctionMap; + + /// This is a virtual root node that has edges to all the global functions - + /// 'main' or functions accessible from other translation units. + CallGraphNode *Root; + + /// The list of nodes that have no parent. These are unreachable from Root. + /// Declarations can get to this list due to impressions in the graph, for + /// example, we do not track functions whose addresses were taken. + llvm::SetVector<CallGraphNode *> ParentlessNodes; + +public: + CallGraph(); + ~CallGraph(); + + /// \brief Populate the call graph with the functions in the given + /// declaration. + /// + /// Recursively walks the declaration to find all the dependent Decls as well. + void addToCallGraph(Decl *D) { + TraverseDecl(D); + } + + /// \brief Determine if a declaration should be included in the graph. + static bool includeInGraph(const Decl *D); + + /// \brief Lookup the node for the given declaration. + CallGraphNode *getNode(const Decl *) const; + + /// \brief Lookup the node for the given declaration. If none found, insert + /// one into the graph. + CallGraphNode *getOrInsertNode(Decl *); + + /// Iterators through all the elements in the graph. Note, this gives + /// non-deterministic order. + typedef FunctionMapTy::iterator iterator; + typedef FunctionMapTy::const_iterator const_iterator; + iterator begin() { return FunctionMap.begin(); } + iterator end() { return FunctionMap.end(); } + const_iterator begin() const { return FunctionMap.begin(); } + const_iterator end() const { return FunctionMap.end(); } + + /// \brief Get the number of nodes in the graph. + unsigned size() const { return FunctionMap.size(); } + + /// \ brief Get the virtual root of the graph, all the functions available + /// externally are represented as callees of the node. + CallGraphNode *getRoot() const { return Root; } + + /// Iterators through all the nodes of the graph that have no parent. These + /// are the unreachable nodes, which are either unused or are due to us + /// failing to add a call edge due to the analysis imprecision. + typedef llvm::SetVector<CallGraphNode *>::iterator nodes_iterator; + typedef llvm::SetVector<CallGraphNode *>::const_iterator const_nodes_iterator; + nodes_iterator parentless_begin() { return ParentlessNodes.begin(); } + nodes_iterator parentless_end() { return ParentlessNodes.end(); } + const_nodes_iterator + parentless_begin() const { return ParentlessNodes.begin(); } + const_nodes_iterator + parentless_end() const { return ParentlessNodes.end(); } + + void print(raw_ostream &os) const; + void dump() const; + void viewGraph() const; + + /// Part of recursive declaration visitation. + bool VisitFunctionDecl(FunctionDecl *FD) { + // We skip function template definitions, as their semantics is + // only determined when they are instantiated. + if (includeInGraph(FD)) + // If this function has external linkage, anything could call it. + // Note, we are not precise here. For example, the function could have + // its address taken. + addNodeForDecl(FD, FD->isGlobal()); + return true; + } + + /// Part of recursive declaration visitation. + bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { + if (includeInGraph(MD)) + addNodeForDecl(MD, true); + return true; + } + +private: + /// \brief Add the given declaration to the call graph. + void addNodeForDecl(Decl *D, bool IsGlobal); + + /// \brief Allocate a new node in the graph. + CallGraphNode *allocateNewNode(Decl *); +}; + +class CallGraphNode { +public: + typedef CallGraphNode* CallRecord; + +private: + /// \brief The function/method declaration. + Decl *FD; + + /// \brief The list of functions called from this node. + // Small vector might be more efficient since we are only tracking functions + // whose definition is in the current TU. + llvm::SmallVector<CallRecord, 5> CalledFunctions; + +public: + CallGraphNode(Decl *D) : FD(D) {} + + typedef llvm::SmallVector<CallRecord, 5>::iterator iterator; + typedef llvm::SmallVector<CallRecord, 5>::const_iterator const_iterator; + + /// Iterators through all the callees/children of the node. + inline iterator begin() { return CalledFunctions.begin(); } + inline iterator end() { return CalledFunctions.end(); } + inline const_iterator begin() const { return CalledFunctions.begin(); } + inline const_iterator end() const { return CalledFunctions.end(); } + + inline bool empty() const {return CalledFunctions.empty(); } + inline unsigned size() const {return CalledFunctions.size(); } + + void addCallee(CallGraphNode *N, CallGraph *CG) { + CalledFunctions.push_back(N); + CG->ParentlessNodes.remove(N); + } + + Decl *getDecl() const { return FD; } + + StringRef getName() const; + + void print(raw_ostream &os) const; + void dump() const; +}; + +} // end clang namespace + +// Graph traits for iteration, viewing. +namespace llvm { +template <> struct GraphTraits<clang::CallGraphNode*> { + typedef clang::CallGraphNode NodeType; + typedef clang::CallGraphNode::CallRecord CallRecordTy; + typedef std::pointer_to_unary_function<CallRecordTy, + clang::CallGraphNode*> CGNDerefFun; + static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; } + typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType; + static inline ChildIteratorType child_begin(NodeType *N) { + return map_iterator(N->begin(), CGNDerefFun(CGNDeref)); + } + static inline ChildIteratorType child_end (NodeType *N) { + return map_iterator(N->end(), CGNDerefFun(CGNDeref)); + } + static clang::CallGraphNode *CGNDeref(CallRecordTy P) { + return P; + } +}; + +template <> struct GraphTraits<const clang::CallGraphNode*> { + typedef const clang::CallGraphNode NodeType; + typedef NodeType::const_iterator ChildIteratorType; + static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; } + static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();} + static inline ChildIteratorType child_end (NodeType *N) { return N->end(); } +}; + +template <> struct GraphTraits<clang::CallGraph*> + : public GraphTraits<clang::CallGraphNode*> { + + static NodeType *getEntryNode(clang::CallGraph *CGN) { + return CGN->getRoot(); // Start at the external node! + } + typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy; + typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun; + // nodes_iterator/begin/end - Allow iteration over all nodes in the graph + typedef mapped_iterator<clang::CallGraph::iterator, DerefFun> nodes_iterator; + + static nodes_iterator nodes_begin(clang::CallGraph *CG) { + return map_iterator(CG->begin(), DerefFun(CGdereference)); + } + static nodes_iterator nodes_end (clang::CallGraph *CG) { + return map_iterator(CG->end(), DerefFun(CGdereference)); + } + static clang::CallGraphNode &CGdereference(PairTy P) { + return *(P.second); + } + + static unsigned size(clang::CallGraph *CG) { + return CG->size(); + } +}; + +template <> struct GraphTraits<const clang::CallGraph*> : + public GraphTraits<const clang::CallGraphNode*> { + static NodeType *getEntryNode(const clang::CallGraph *CGN) { + return CGN->getRoot(); + } + typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy; + typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun; + // nodes_iterator/begin/end - Allow iteration over all nodes in the graph + typedef mapped_iterator<clang::CallGraph::const_iterator, + DerefFun> nodes_iterator; + + static nodes_iterator nodes_begin(const clang::CallGraph *CG) { + return map_iterator(CG->begin(), DerefFun(CGdereference)); + } + static nodes_iterator nodes_end(const clang::CallGraph *CG) { + return map_iterator(CG->end(), DerefFun(CGdereference)); + } + static clang::CallGraphNode &CGdereference(PairTy P) { + return *(P.second); + } + + static unsigned size(const clang::CallGraph *CG) { + return CG->size(); + } +}; + +} // end llvm namespace + +#endif diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h index fa8afcc..e6a2f13 100644 --- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h +++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -14,25 +14,15 @@ #ifndef LLVM_CLANG_ANALYSIS_DS_COCOA #define LLVM_CLANG_ANALYSIS_DS_COCOA -#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" namespace clang { class FunctionDecl; -class ObjCMethodDecl; class QualType; namespace ento { namespace cocoa { - - enum NamingConvention { NoConvention, CreateRule, InitRule }; - - NamingConvention deriveNamingConvention(Selector S, const ObjCMethodDecl *MD); - - static inline bool followsFundamentalRule(Selector S, - const ObjCMethodDecl *MD) { - return deriveNamingConvention(S, MD) == CreateRule; - } bool isRefType(QualType RetTy, StringRef Prefix, StringRef Name = StringRef()); diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 7ec4ecd..b2200c6 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -19,6 +19,7 @@ #include "clang/Analysis/CFG.h" #include "llvm/Support/DataTypes.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/StringRef.h" @@ -28,7 +29,7 @@ namespace clang { -class AnalysisContext; +class AnalysisDeclContext; class FunctionDecl; class LocationContext; class ProgramPointTag; @@ -51,44 +52,72 @@ public: CallEnterKind, CallExitKind, MinPostStmtKind = PostStmtKind, - MaxPostStmtKind = CallExitKind }; + MaxPostStmtKind = CallExitKind, + EpsilonKind}; private: - std::pair<const void *, const void *> Data; - Kind K; + llvm::PointerIntPair<const void *, 2, unsigned> Data1; + llvm::PointerIntPair<const void *, 2, unsigned> Data2; // The LocationContext could be NULL to allow ProgramPoint to be used in // context insensitive analysis. - const LocationContext *L; + llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; + const ProgramPointTag *Tag; ProgramPoint(); protected: - ProgramPoint(const void *P, Kind k, const LocationContext *l, + 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, + : Data1(P, ((unsigned) k) & 0x3), + Data2(0, (((unsigned) k) >> 2) & 0x3), + L(l, (((unsigned) k) >> 4) & 0x3), + Tag(tag) { + assert(getKind() == k); + assert(getLocationContext() == l); + assert(getData1() == P); + } + + 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) {} + : Data1(P1, ((unsigned) k) & 0x3), + Data2(P2, (((unsigned) k) >> 2) & 0x3), + L(l, (((unsigned) k) >> 4) & 0x3), + Tag(tag) {} protected: - const void *getData1() const { return Data.first; } - const void *getData2() const { return Data.second; } + const void *getData1() const { return Data1.getPointer(); } + const void *getData2() const { return Data2.getPointer(); } + void setData2(const void *d) { Data2.setPointer(d); } 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); + return ProgramPoint(getData1(), getData2(), getKind(), + getLocationContext(), tag); } - Kind getKind() const { return K; } + Kind getKind() const { + unsigned x = L.getInt(); + x <<= 2; + x |= Data2.getInt(); + x <<= 2; + x |= Data1.getInt(); + return (Kind) x; + } const ProgramPointTag *getTag() const { return Tag; } - const LocationContext *getLocationContext() const { return L; } + const LocationContext *getLocationContext() const { + return L.getPointer(); + } // For use with DenseMap. This hash is probably slow. unsigned getHashValue() const { @@ -100,25 +129,30 @@ public: static bool classof(const ProgramPoint*) { return true; } bool operator==(const ProgramPoint & RHS) const { - return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag; + return Data1 == Data1 && + Data2 == RHS.Data2 && + L == RHS.L && + Tag == RHS.Tag; } bool operator!=(const ProgramPoint &RHS) const { - return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag; + return Data1 != RHS.Data1 || + Data2 != RHS.Data2 || + L != RHS.L || + Tag != RHS.Tag; } void Profile(llvm::FoldingSetNodeID& ID) const { - ID.AddInteger((unsigned) K); - ID.AddPointer(Data.first); - ID.AddPointer(Data.second); - ID.AddPointer(L); + ID.AddInteger((unsigned) getKind()); + ID.AddPointer(getData1()); + ID.AddPointer(getData2()); + ID.AddPointer(getLocationContext()); ID.AddPointer(Tag); } static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, const LocationContext *LC, const ProgramPointTag *tag); - }; class BlockEntrance : public ProgramPoint { @@ -195,7 +229,7 @@ public: class PostStmt : public StmtPoint { protected: PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, - const ProgramPointTag *tag =0) + const ProgramPointTag *tag = 0) : StmtPoint(S, data, k, L, tag) {} public: @@ -270,15 +304,29 @@ public: } }; +/// \class Represents a program point after a store evaluation. class PostStore : public PostStmt { public: - PostStore(const Stmt *S, const LocationContext *L, + /// Construct the post store point. + /// \param Loc can be used to store the information about the location + /// used in the form it was uttered in the code. + PostStore(const Stmt *S, const LocationContext *L, const void *Loc, const ProgramPointTag *tag = 0) - : PostStmt(S, PostStoreKind, L, tag) {} + : PostStmt(S, PostStoreKind, L, tag) { + assert(getData2() == 0); + setData2(Loc); + } static bool classof(const ProgramPoint* Location) { return Location->getKind() == PostStoreKind; } + + /// \brief Returns the information about the location used in the store, + /// how it was uttered in the code. + const void *getLocationValue() const { + return getData2(); + } + }; class PostLValue : public PostStmt { @@ -365,6 +413,21 @@ public: } }; +/// This is a meta program point, which should be skipped by all the diagnostic +/// reasoning etc. +class EpsilonPoint : public ProgramPoint { +public: + EpsilonPoint(const LocationContext *L, const void *Data1, + const void *Data2 = 0, const ProgramPointTag *tag = 0) + : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} + + const void *getData() const { return getData1(); } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == EpsilonKind; + } +}; + /// 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. diff --git a/include/clang/Analysis/Support/SaveAndRestore.h b/include/clang/Analysis/Support/SaveAndRestore.h deleted file mode 100644 index f720639..0000000 --- a/include/clang/Analysis/Support/SaveAndRestore.h +++ /dev/null @@ -1,47 +0,0 @@ -//===-- SaveAndRestore.h - Utility -------------------------------*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides utility classes that uses RAII to save and restore -// values. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_SAVERESTORE -#define LLVM_CLANG_ANALYSIS_SAVERESTORE - -namespace clang { - -// SaveAndRestore - A utility class that uses RAII to save and restore -// the value of a variable. -template<typename T> -struct SaveAndRestore { - SaveAndRestore(T& x) : X(x), old_value(x) {} - SaveAndRestore(T& x, const T &new_value) : X(x), old_value(x) { - X = new_value; - } - ~SaveAndRestore() { X = old_value; } - T get() { return old_value; } -private: - T& X; - T old_value; -}; - -// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old -// value of a variable is saved, and during the dstor the old value is -// or'ed with the new value. -struct SaveOr { - SaveOr(bool& x) : X(x), old_value(x) { x = false; } - ~SaveOr() { X |= old_value; } -private: - bool& X; - const bool old_value; -}; - -} -#endif diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index 5c5ec2d..97eb287 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -66,6 +66,7 @@ public: DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl? DISPATCH_CASE(CXXRecord) DISPATCH_CASE(Enum) + DISPATCH_CASE(Field) DISPATCH_CASE(UsingDirective) DISPATCH_CASE(Using) default: @@ -82,8 +83,8 @@ public: DEFAULT_DISPATCH(Typedef) DEFAULT_DISPATCH(Record) DEFAULT_DISPATCH(Enum) + DEFAULT_DISPATCH(Field) DEFAULT_DISPATCH(ObjCInterface) - DEFAULT_DISPATCH(ObjCClass) DEFAULT_DISPATCH(ObjCMethod) DEFAULT_DISPATCH(ObjCProtocol) DEFAULT_DISPATCH(ObjCCategory) |