diff options
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r-- | include/clang/Analysis/Analyses/FormatString.h | 13 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/LiveVariables.h | 3 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/UninitializedValuesV2.h | 40 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisContext.h | 37 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Analysis/CFG.h | 409 | ||||
-rw-r--r-- | include/clang/Analysis/DomainSpecific/CocoaConventions.h | 40 | ||||
-rw-r--r-- | include/clang/Analysis/FlowSensitive/DataflowSolver.h | 18 | ||||
-rw-r--r-- | include/clang/Analysis/ProgramPoint.h | 48 | ||||
-rw-r--r-- | include/clang/Analysis/Support/BumpVector.h | 29 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h | 4 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtVisitor.h | 5 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGStmtVisitor.h | 4 |
13 files changed, 554 insertions, 98 deletions
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 280b126..7cc76a8 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -379,6 +379,7 @@ using analyze_format_string::OptionalAmount; using analyze_format_string::OptionalFlag; class PrintfSpecifier : public analyze_format_string::FormatSpecifier { + OptionalFlag HasThousandsGrouping; // ''', POSIX extension. OptionalFlag IsLeftJustified; // '-' OptionalFlag HasPlusPrefix; // '+' OptionalFlag HasSpacePrefix; // ' ' @@ -388,8 +389,8 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier { public: PrintfSpecifier() : FormatSpecifier(/* isPrintf = */ true), - IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), - HasAlternativeForm("#"), HasLeadingZeroes("0") {} + HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"), + HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {} static PrintfSpecifier Parse(const char *beg, const char *end); @@ -397,6 +398,10 @@ public: void setConversionSpecifier(const PrintfConversionSpecifier &cs) { CS = cs; } + void setHasThousandsGrouping(const char *position) { + HasThousandsGrouping = true; + HasThousandsGrouping.setPosition(position); + } void setIsLeftJustified(const char *position) { IsLeftJustified = true; IsLeftJustified.setPosition(position); @@ -445,6 +450,9 @@ public: /// more than one type. ArgTypeResult getArgType(ASTContext &Ctx) const; + const OptionalFlag &hasThousandsGrouping() const { + return HasThousandsGrouping; + } const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } @@ -465,6 +473,7 @@ public: bool hasValidLeadingZeros() const; bool hasValidSpacePrefix() const; bool hasValidLeftJustified() const; + bool hasValidThousandsGroupingPrefix() const; bool hasValidPrecision() const; bool hasValidFieldWidth() const; diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 237fe14..fbbd261 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -55,7 +55,8 @@ struct LiveVariables_ValueTypes { /// ObserveStmt - A callback invoked right before invoking the /// liveness transfer function on the given statement. - virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD, + virtual void ObserveStmt(Stmt* S, const CFGBlock *currentBlock, + const AnalysisDataTy& AD, const ValTy& V) {} virtual void ObserverKill(DeclRefExpr* DR) {} diff --git a/include/clang/Analysis/Analyses/UninitializedValuesV2.h b/include/clang/Analysis/Analyses/UninitializedValuesV2.h new file mode 100644 index 0000000..c1fe040 --- /dev/null +++ b/include/clang/Analysis/Analyses/UninitializedValuesV2.h @@ -0,0 +1,40 @@ +//= UninitializedValuesV2.h - Finding uses of uninitialized values --*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines APIs for invoking and reported uninitialized values +// warnings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_UNINIT_VALS_H +#define LLVM_CLANG_UNINIT_VALS_H + +namespace clang { + +class AnalysisContext; +class CFG; +class DeclContext; +class Expr; +class VarDecl; + +class UninitVariablesHandler { +public: + UninitVariablesHandler() {} + virtual ~UninitVariablesHandler(); + + virtual void handleUseOfUninitVariable(const Expr *ex, + const VarDecl *vd) {} +}; + +void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, + AnalysisContext &ac, + UninitVariablesHandler &handler); + +} +#endif diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 7d4d25f..2ecbfdc 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H #include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerUnion.h" @@ -56,15 +57,20 @@ class AnalysisContext { llvm::BumpPtrAllocator A; bool UseUnoptimizedCFG; bool AddEHEdges; + bool AddImplicitDtors; + bool AddInitializers; public: AnalysisContext(const Decl *d, idx::TranslationUnit *tu, bool useUnoptimizedCFG = false, - bool addehedges = false) + bool addehedges = false, + bool addImplicitDtors = false, + bool addInitializers = false) : D(d), TU(tu), cfg(0), completeCFG(0), builtCFG(false), builtCompleteCFG(false), liveness(0), relaxedLiveness(0), PM(0), PCA(0), ReferencedBlockVars(0), UseUnoptimizedCFG(useUnoptimizedCFG), - AddEHEdges(addehedges) {} + AddEHEdges(addehedges), AddImplicitDtors(addImplicitDtors), + AddInitializers(addInitializers) {} ~AnalysisContext(); @@ -80,13 +86,17 @@ public: bool getAddEHEdges() const { return AddEHEdges; } bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; } + bool getAddImplicitDtors() const { return AddImplicitDtors; } + bool getAddInitializers() const { return AddInitializers; } Stmt *getBody(); CFG *getCFG(); - + /// Return a version of the CFG without any edges pruned. CFG *getUnoptimizedCFG(); + void dumpCFG(); + ParentMap &getParentMap(); PseudoConstantAnalysis *getPseudoConstantAnalysis(); LiveVariables *getLiveVariables(); @@ -106,15 +116,21 @@ class AnalysisContextManager { typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap; ContextMap Contexts; bool UseUnoptimizedCFG; + bool AddImplicitDtors; + bool AddInitializers; public: - AnalysisContextManager(bool useUnoptimizedCFG = false) - : UseUnoptimizedCFG(useUnoptimizedCFG) {} + AnalysisContextManager(bool useUnoptimizedCFG = false, + bool addImplicitDtors = false, bool addInitializers = false) + : UseUnoptimizedCFG(useUnoptimizedCFG), AddImplicitDtors(addImplicitDtors), + AddInitializers(addInitializers) {} ~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; } // Discard all previously created AnalysisContexts. void clear(); @@ -196,9 +212,10 @@ class StackFrameContext : public LocationContext { friend class LocationContextManager; StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, unsigned idx) - : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk), - Index(idx) {} + const Stmt *s, const CFGBlock *blk, + unsigned idx) + : LocationContext(StackFrame, ctx, parent), CallSite(s), + Block(blk), Index(idx) {} public: ~StackFrameContext() {} @@ -282,8 +299,8 @@ public: const StackFrameContext *getStackFrame(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, - unsigned idx); + const Stmt *s, + const CFGBlock *blk, unsigned idx); const ScopeContext *getScope(AnalysisContext *ctx, const LocationContext *parent, diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index e98a3df..295d0a2 100644 --- a/include/clang/Analysis/AnalysisDiagnostic.h +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,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 b7a8e11..b337d74 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -22,14 +22,21 @@ #include "clang/Analysis/Support/BumpVector.h" #include "clang/Basic/SourceLocation.h" #include <cassert> +#include <iterator> namespace llvm { class raw_ostream; } + namespace clang { class Decl; class Stmt; class Expr; + class FieldDecl; + class VarDecl; + class CXXCtorInitializer; + class CXXBaseSpecifier; + class CXXBindTemporaryExpr; class CFG; class PrinterHelper; class LangOptions; @@ -37,19 +44,203 @@ namespace clang { /// CFGElement - Represents a top-level expression in a basic block. class CFGElement { - llvm::PointerIntPair<Stmt *, 2> Data; public: - enum Type { StartScope, EndScope }; - explicit CFGElement() {} - CFGElement(Stmt *S, bool lvalue) : Data(S, lvalue ? 1 : 0) {} - CFGElement(Stmt *S, Type t) : Data(S, t == StartScope ? 2 : 3) {} - Stmt *getStmt() const { return Data.getPointer(); } - bool asLValue() const { return Data.getInt() == 1; } - bool asStartScope() const { return Data.getInt() == 2; } - bool asEndScope() const { return Data.getInt() == 3; } - bool asDtor() const { return Data.getInt() == 4; } + enum Kind { + // main kind + Statement, + Initializer, + ImplicitDtor, + // dtor kind + AutomaticObjectDtor, + BaseDtor, + MemberDtor, + TemporaryDtor, + DTOR_BEGIN = AutomaticObjectDtor + }; + +protected: + // The int bits are used to mark the main kind. + llvm::PointerIntPair<void *, 2> Data1; + // The int bits are used to mark the dtor kind. + llvm::PointerIntPair<void *, 2> Data2; + + CFGElement(void *Ptr, unsigned Int) : Data1(Ptr, Int) {} + CFGElement(void *Ptr1, unsigned Int1, void *Ptr2, unsigned Int2) + : Data1(Ptr1, Int1), Data2(Ptr2, Int2) {} + +public: + CFGElement() {} + + Kind getKind() const { return static_cast<Kind>(Data1.getInt()); } + + Kind getDtorKind() const { + assert(getKind() == ImplicitDtor); + return static_cast<Kind>(Data2.getInt() + DTOR_BEGIN); + } + + bool isValid() const { return Data1.getPointer(); } + + operator bool() const { return isValid(); } + + template<class ElemTy> ElemTy getAs() const { + if (llvm::isa<ElemTy>(this)) + return *static_cast<const ElemTy*>(this); + return ElemTy(); + } + + static bool classof(const CFGElement *E) { return true; } +}; + +class CFGStmt : public CFGElement { +public: + CFGStmt() {} + CFGStmt(Stmt *S) : CFGElement(S, 0) {} + + Stmt *getStmt() const { return static_cast<Stmt *>(Data1.getPointer()); } + operator Stmt*() const { return getStmt(); } - operator bool() const { return getStmt() != 0; } + + static bool classof(const CFGElement *E) { + return E->getKind() == Statement; + } +}; + +/// CFGInitializer - Represents C++ base or member initializer from +/// constructor's initialization list. +class CFGInitializer : public CFGElement { +public: + CFGInitializer() {} + CFGInitializer(CXXCtorInitializer* I) + : CFGElement(I, Initializer) {} + + CXXCtorInitializer* getInitializer() const { + return static_cast<CXXCtorInitializer*>(Data1.getPointer()); + } + operator CXXCtorInitializer*() const { return getInitializer(); } + + static bool classof(const CFGElement *E) { + return E->getKind() == Initializer; + } +}; + +/// CFGImplicitDtor - Represents C++ object destructor implicitly generated +/// by compiler on various occasions. +class CFGImplicitDtor : public CFGElement { +protected: + CFGImplicitDtor(unsigned K, void* P, void* S) + : CFGElement(P, ImplicitDtor, S, K - DTOR_BEGIN) {} + +public: + CFGImplicitDtor() {} + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor; + } +}; + +/// CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated +/// for automatic object or temporary bound to const reference at the point +/// of leaving its local scope. +class CFGAutomaticObjDtor: public CFGImplicitDtor { +public: + CFGAutomaticObjDtor() {} + CFGAutomaticObjDtor(VarDecl* VD, Stmt* S) + : CFGImplicitDtor(AutomaticObjectDtor, VD, S) {} + + VarDecl* getVarDecl() const { + return static_cast<VarDecl*>(Data1.getPointer()); + } + + // Get statement end of which triggered the destructor call. + Stmt* getTriggerStmt() const { + return static_cast<Stmt*>(Data2.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor && + E->getDtorKind() == AutomaticObjectDtor; + } +}; + +/// CFGBaseDtor - Represents C++ object destructor implicitly generated for +/// base object in destructor. +class CFGBaseDtor : public CFGImplicitDtor { +public: + CFGBaseDtor() {} + CFGBaseDtor(const CXXBaseSpecifier *BS) + : CFGImplicitDtor(BaseDtor, const_cast<CXXBaseSpecifier*>(BS), NULL) {} + + const CXXBaseSpecifier *getBaseSpecifier() const { + return static_cast<const CXXBaseSpecifier*>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor && E->getDtorKind() == BaseDtor; + } +}; + +/// CFGMemberDtor - Represents C++ object destructor implicitly generated for +/// member object in destructor. +class CFGMemberDtor : public CFGImplicitDtor { +public: + CFGMemberDtor() {} + CFGMemberDtor(FieldDecl *FD) + : CFGImplicitDtor(MemberDtor, FD, NULL) {} + + FieldDecl *getFieldDecl() const { + return static_cast<FieldDecl*>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor && E->getDtorKind() == MemberDtor; + } +}; + +/// CFGTemporaryDtor - Represents C++ object destructor implicitly generated +/// at the end of full expression for temporary object. +class CFGTemporaryDtor : public CFGImplicitDtor { +public: + CFGTemporaryDtor() {} + CFGTemporaryDtor(CXXBindTemporaryExpr *E) + : CFGImplicitDtor(TemporaryDtor, E, NULL) {} + + CXXBindTemporaryExpr *getBindTemporaryExpr() const { + return static_cast<CXXBindTemporaryExpr *>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == ImplicitDtor && E->getDtorKind() == TemporaryDtor; + } +}; + +/// CFGTerminator - Represents CFGBlock terminator statement. +/// +/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch +/// in control flow of destructors of temporaries. In this case terminator +/// statement is the same statement that branches control flow in evaluation +/// of matching full expression. +class CFGTerminator { + llvm::PointerIntPair<Stmt *, 1> Data; +public: + CFGTerminator() {} + CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false) + : Data(S, TemporaryDtorsBranch) {} + + Stmt *getStmt() { return Data.getPointer(); } + const Stmt *getStmt() const { return Data.getPointer(); } + + bool isTemporaryDtorsBranch() const { return Data.getInt(); } + + operator Stmt *() { return getStmt(); } + operator const Stmt *() const { return getStmt(); } + + Stmt *operator->() { return getStmt(); } + const Stmt *operator->() const { return getStmt(); } + + Stmt &operator*() { return *getStmt(); } + const Stmt &operator*() const { return *getStmt(); } + + operator bool() const { return getStmt(); } }; /// CFGBlock - Represents a single basic block in a source-level CFG. @@ -77,11 +268,11 @@ public: /// &&, || expression that uses result of && or ||, RHS /// class CFGBlock { - class StatementList { + class ElementList { typedef BumpVector<CFGElement> ImplTy; ImplTy Impl; public: - StatementList(BumpVectorContext &C) : Impl(C, 4) {} + ElementList(BumpVectorContext &C) : Impl(C, 4) {} typedef std::reverse_iterator<ImplTy::iterator> iterator; typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; @@ -89,6 +280,11 @@ class CFGBlock { 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) { + return Impl.insert(I, Cnt, E, C); + } + CFGElement front() const { return Impl.back(); } CFGElement back() const { return Impl.front(); } @@ -111,7 +307,7 @@ class CFGBlock { }; /// Stmts - The set of statements in the basic block. - StatementList Stmts; + ElementList Elements; /// Label - An (optional) label that prefixes the executable /// statements in the block. When this variable is non-NULL, it is @@ -121,7 +317,7 @@ class CFGBlock { /// Terminator - The terminator for a basic block that /// indicates the type of control-flow that occurs between a block /// and its successors. - Stmt *Terminator; + CFGTerminator Terminator; /// LoopTarget - Some blocks are used to represent the "loop edge" to /// the start of a loop from within the loop body. This Stmt* will be @@ -140,33 +336,33 @@ class CFGBlock { public: explicit CFGBlock(unsigned blockid, BumpVectorContext &C) - : Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), + : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), BlockID(blockid), Preds(C, 1), Succs(C, 1) {} ~CFGBlock() {} // Statement iterators - typedef StatementList::iterator iterator; - typedef StatementList::const_iterator const_iterator; - typedef StatementList::reverse_iterator reverse_iterator; - typedef StatementList::const_reverse_iterator const_reverse_iterator; + typedef ElementList::iterator iterator; + typedef ElementList::const_iterator const_iterator; + typedef ElementList::reverse_iterator reverse_iterator; + typedef ElementList::const_reverse_iterator const_reverse_iterator; - CFGElement front() const { return Stmts.front(); } - CFGElement back() const { return Stmts.back(); } + CFGElement front() const { return Elements.front(); } + CFGElement back() const { return Elements.back(); } - iterator begin() { return Stmts.begin(); } - iterator end() { return Stmts.end(); } - const_iterator begin() const { return Stmts.begin(); } - const_iterator end() const { return Stmts.end(); } + iterator begin() { return Elements.begin(); } + iterator end() { return Elements.end(); } + const_iterator begin() const { return Elements.begin(); } + const_iterator end() const { return Elements.end(); } - reverse_iterator rbegin() { return Stmts.rbegin(); } - reverse_iterator rend() { return Stmts.rend(); } - const_reverse_iterator rbegin() const { return Stmts.rbegin(); } - const_reverse_iterator rend() const { return Stmts.rend(); } + reverse_iterator rbegin() { return Elements.rbegin(); } + reverse_iterator rend() { return Elements.rend(); } + const_reverse_iterator rbegin() const { return Elements.rbegin(); } + const_reverse_iterator rend() const { return Elements.rend(); } - unsigned size() const { return Stmts.size(); } - bool empty() const { return Stmts.empty(); } + unsigned size() const { return Elements.size(); } + bool empty() const { return Elements.empty(); } - CFGElement operator[](size_t i) const { return Stmts[i]; } + CFGElement operator[](size_t i) const { return Elements[i]; } // CFG iterators typedef AdjacentBlocks::iterator pred_iterator; @@ -205,14 +401,67 @@ public: unsigned pred_size() const { return Preds.size(); } bool pred_empty() const { return Preds.empty(); } + + class FilterOptions { + public: + FilterOptions() { + IgnoreDefaultsWithCoveredEnums = 0; + } + + unsigned IgnoreDefaultsWithCoveredEnums : 1; + }; + + static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src, + const CFGBlock *Dst); + + template <typename IMPL, bool IsPred> + class FilteredCFGBlockIterator { + private: + IMPL I, E; + const FilterOptions F; + const CFGBlock *From; + public: + explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e, + const CFGBlock *from, + const FilterOptions &f) + : I(i), E(e), F(f), From(from) {} + + bool hasMore() const { return I != E; } + + FilteredCFGBlockIterator &operator++() { + do { ++I; } while (hasMore() && Filter(*I)); + return *this; + } + + const CFGBlock *operator*() const { return *I; } + private: + bool Filter(const CFGBlock *To) { + return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To); + } + }; + + typedef FilteredCFGBlockIterator<const_pred_iterator, true> + filtered_pred_iterator; + + typedef FilteredCFGBlockIterator<const_succ_iterator, false> + filtered_succ_iterator; + + filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const { + return filtered_pred_iterator(pred_begin(), pred_end(), this, f); + } + + filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const { + return filtered_succ_iterator(succ_begin(), succ_end(), this, f); + } + // Manipulation of block contents void setTerminator(Stmt* Statement) { Terminator = Statement; } void setLabel(Stmt* Statement) { Label = Statement; } void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; } - Stmt* getTerminator() { return Terminator; } - const Stmt* getTerminator() const { return Terminator; } + CFGTerminator getTerminator() { return Terminator; } + const CFGTerminator getTerminator() const { return Terminator; } Stmt* getTerminatorCondition(); @@ -239,17 +488,39 @@ public: Succs.push_back(Block, C); } - void appendStmt(Stmt* Statement, BumpVectorContext &C, bool asLValue) { - Stmts.push_back(CFGElement(Statement, asLValue), C); - } - void StartScope(Stmt* S, BumpVectorContext &C) { - Stmts.push_back(CFGElement(S, CFGElement::StartScope), C); + void appendStmt(Stmt* statement, BumpVectorContext &C) { + Elements.push_back(CFGStmt(statement), C); + } + + void appendInitializer(CXXCtorInitializer *initializer, + BumpVectorContext& C) { + Elements.push_back(CFGInitializer(initializer), C); } - void EndScope(Stmt* S, BumpVectorContext &C) { - Stmts.push_back(CFGElement(S, CFGElement::EndScope), C); + + void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) { + Elements.push_back(CFGBaseDtor(BS), C); } -}; + void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) { + Elements.push_back(CFGMemberDtor(FD), C); + } + + void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) { + Elements.push_back(CFGTemporaryDtor(E), 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) { + return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C)); + } + iterator insertAutomaticObjDtor(iterator I, VarDecl* VD, Stmt* S) { + *I = CFGAutomaticObjDtor(VD, S); + return ++I; + } +}; /// CFG - Represents a source-level, intra-procedural CFG that represents the /// control-flow of a Stmt. The Stmt can represent an entire function body, @@ -264,13 +535,24 @@ public: // CFG Construction & Manipulation. //===--------------------------------------------------------------------===// + class BuildOptions { + public: + bool PruneTriviallyFalseEdges:1; + bool AddEHEdges:1; + bool AddInitializers:1; + bool AddImplicitDtors:1; + + BuildOptions() + : 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, - bool pruneTriviallyFalseEdges = true, - bool AddEHEdges = false, - bool AddScopes = false /* NOT FULLY IMPLEMENTED. - NOT READY FOR GENERAL USE. */); + BuildOptions BO = BuildOptions()); /// createBlock - Create a new block in the CFG. The CFG owns the block; /// the caller should not directly free it. @@ -324,8 +606,10 @@ public: void VisitBlockStmts(CALLBACK& O) const { for (const_iterator I=begin(), E=end(); I != E; ++I) for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end(); - BI != BE; ++BI) - O(*BI); + BI != BE; ++BI) { + if (CFGStmt S = BI->getAs<CFGStmt>()) + O(S); + } } //===--------------------------------------------------------------------===// @@ -340,7 +624,10 @@ 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); unsigned getNumBlkExprs(); @@ -398,18 +685,22 @@ private: namespace llvm { -/// Implement simplify_type for CFGElement, so that we can dyn_cast from -/// CFGElement to a specific Stmt class. -template <> struct simplify_type<const ::clang::CFGElement> { - typedef ::clang::Stmt* SimpleType; - static SimpleType getSimplifiedValue(const ::clang::CFGElement &Val) { +/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from +/// CFGTerminator to a specific Stmt class. +template <> struct simplify_type<const ::clang::CFGTerminator> { + typedef const ::clang::Stmt *SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) { return Val.getStmt(); } }; - -template <> struct simplify_type< ::clang::CFGElement> - : public simplify_type<const ::clang::CFGElement> {}; - + +template <> struct simplify_type< ::clang::CFGTerminator> { + typedef ::clang::Stmt *SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) { + return const_cast<SimpleType>(Val.getStmt()); + } +}; + // Traits for: CFGBlock template <> struct GraphTraits< ::clang::CFGBlock* > { diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h new file mode 100644 index 0000000..7e6e381 --- /dev/null +++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -0,0 +1,40 @@ +//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA +#define LLVM_CLANG_ANALYSIS_DS_COCOA + +#include "clang/AST/Type.h" + +namespace clang { +namespace ento { +namespace cocoa { + + enum NamingConvention { NoConvention, CreateRule, InitRule }; + + NamingConvention deriveNamingConvention(Selector S, bool ignorePrefix = true); + + static inline bool followsFundamentalRule(Selector S) { + return deriveNamingConvention(S) == CreateRule; + } + + bool isRefType(QualType RetTy, llvm::StringRef Prefix, + llvm::StringRef Name = llvm::StringRef()); + + bool isCFObjectRef(QualType T); + + bool isCocoaObjectRef(QualType T); + +}}} + +#endif diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h index 9375db0..d75d333 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h +++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -273,8 +273,13 @@ private: void ProcessBlock(const CFGBlock* B, bool recordStmtValues, dataflow::forward_analysis_tag) { - for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) - ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); + TF.setCurrentBlock(B); + + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) { + CFGElement El = *I; + if (CFGStmt S = El.getAs<CFGStmt>()) + ProcessStmt(S, recordStmtValues, AnalysisDirTag()); + } TF.VisitTerminator(const_cast<CFGBlock*>(B)); } @@ -282,10 +287,15 @@ private: void ProcessBlock(const CFGBlock* B, bool recordStmtValues, dataflow::backward_analysis_tag) { + TF.setCurrentBlock(B); + TF.VisitTerminator(const_cast<CFGBlock*>(B)); - for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) - ProcessStmt(*I, recordStmtValues, AnalysisDirTag()); + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) { + CFGElement El = *I; + if (CFGStmt S = El.getAs<CFGStmt>()) + ProcessStmt(S, recordStmtValues, AnalysisDirTag()); + } } void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) { diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index ba303de..54cfc3d 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -17,7 +17,7 @@ #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Casting.h" @@ -44,6 +44,7 @@ public: PostPurgeDeadSymbolsKind, PostStmtCustomKind, PostLValueKind, + PostInitializerKind, CallEnterKind, CallExitKind, MinPostStmtKind = PostStmtKind, @@ -70,11 +71,12 @@ protected: protected: const void* getData1() const { return Data.first; } const void* getData2() const { return Data.second; } - const void *getTag() const { return Tag; } public: Kind getKind() const { return K; } + const void *getTag() const { return Tag; } + const LocationContext *getLocationContext() const { return L; } // For use with DenseMap. This hash is probably slow. @@ -118,10 +120,12 @@ public: return B->empty() ? CFGElement() : B->front(); } - const Stmt *getFirstStmt() const { - return getFirstElement().getStmt(); + /// 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; } @@ -136,11 +140,6 @@ public: return reinterpret_cast<const CFGBlock*>(getData1()); } - const Stmt* getLastStmt() const { - const CFGBlock* B = getBlock(); - return B->empty() ? CFGElement() : B->back(); - } - const Stmt* getTerminator() const { return getBlock()->getTerminator(); } @@ -183,14 +182,15 @@ public: class PostStmt : public StmtPoint { protected: - PostStmt(const Stmt* S, Kind k, const LocationContext *L, const void *tag = 0) - : StmtPoint(S, NULL, k, L, tag) {} - PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L, const void *tag =0) : StmtPoint(S, data, k, L, tag) {} public: + explicit PostStmt(const Stmt* S, Kind k, + const LocationContext *L, const void *tag = 0) + : StmtPoint(S, NULL, k, L, tag) {} + explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0) : StmtPoint(S, NULL, PostStmtKind, L, tag) {} @@ -313,19 +313,29 @@ public: } }; +class PostInitializer : public ProgramPoint { +public: + PostInitializer(const CXXCtorInitializer *I, + const LocationContext *L) + : ProgramPoint(I, PostInitializerKind, L) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == PostInitializerKind; + } +}; + class CallEnter : public StmtPoint { public: - // L is caller's location context. AC is callee's AnalysisContext. - CallEnter(const Stmt *S, const AnalysisContext *AC, const LocationContext *L) - : StmtPoint(S, AC, CallEnterKind, L, 0) {} + CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, + const LocationContext *callerCtx) + : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {} const Stmt *getCallExpr() const { return static_cast<const Stmt *>(getData1()); } - AnalysisContext *getCalleeContext() const { - return const_cast<AnalysisContext *>( - static_cast<const AnalysisContext *>(getData2())); + const StackFrameContext *getCalleeContext() const { + return static_cast<const StackFrameContext *>(getData2()); } static bool classof(const ProgramPoint *Location) { diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h index 7cd4812..83532e6 100644 --- a/include/clang/Analysis/Support/BumpVector.h +++ b/include/clang/Analysis/Support/BumpVector.h @@ -24,6 +24,7 @@ #include "llvm/ADT/PointerIntPair.h" #include <algorithm> #include <cstring> +#include <iterator> #include <memory> namespace clang { @@ -155,7 +156,25 @@ public: grow(C); goto Retry; } - + + /// insert - Insert some number of copies of element into a position. Return + /// iterator to position after last inserted copy. + iterator insert(iterator I, size_t Cnt, const_reference E, + BumpVectorContext &C) { + assert (I >= Begin && I <= End && "Iterator out of bounds."); + if (End + Cnt <= Capacity) { + Retry: + move_range_right(I, End, Cnt); + construct_range(I, I + Cnt, E); + End += Cnt; + return I + Cnt; + } + ptrdiff_t D = I - Begin; + grow(C, size() + Cnt); + I = Begin + D; + goto Retry; + } + void reserve(BumpVectorContext &C, unsigned N) { if (unsigned(Capacity-Begin) < N) grow(C, N); @@ -181,6 +200,14 @@ private: E->~T(); } } + + void move_range_right(T *S, T *E, size_t D) { + for (T *I = E + D - 1, *IL = S + D - 1; I != IL; --I) { + --E; + new (I) T(*E); + E->~T(); + } + } }; // Define this out-of-line to dissuade the C++ compiler from inlining it. diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index f20a49a..95f4ace 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -66,6 +66,8 @@ public: DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl? DISPATCH_CASE(CXXRecord) DISPATCH_CASE(Enum) + DISPATCH_CASE(UsingDirective) + DISPATCH_CASE(Using) default: assert(false && "Subtype of ScopedDecl not handled."); } @@ -85,6 +87,8 @@ public: DEFAULT_DISPATCH(ObjCMethod) DEFAULT_DISPATCH(ObjCProtocol) DEFAULT_DISPATCH(ObjCCategory) + DEFAULT_DISPATCH(UsingDirective) + DEFAULT_DISPATCH(Using) void VisitCXXRecordDecl(CXXRecordDecl *D) { static_cast<ImplClass*>(this)->VisitRecordDecl(D); diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h index 75a4ac6..bb7cf0b 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -26,6 +26,11 @@ public: static_cast< ImplClass* >(this)->VisitChildren(S); } + void VisitCompoundStmt(CompoundStmt *S) { + // Do nothing. Everything in a CompoundStmt is inlined + // into the CFG. + } + void VisitConditionVariableInit(Stmt *S) { assert(S == this->getCurrentBlkStmt()); VarDecl *CondVar = 0; diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h index 6421f18..d197e69 100644 --- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -80,6 +80,7 @@ public: DISPATCH_CASE(StmtExpr) DISPATCH_CASE(ConditionalOperator) + DISPATCH_CASE(BinaryConditionalOperator) DISPATCH_CASE(ObjCForCollectionStmt) case Stmt::BinaryOperatorClass: { @@ -102,6 +103,7 @@ public: DEFAULT_BLOCKSTMT_VISIT(StmtExpr) DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) + DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator) RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); @@ -155,7 +157,7 @@ public: } } - for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) + for (Stmt::child_range I = S->children(); I; ++I) if (*I) static_cast<ImplClass*>(this)->Visit(*I); } }; |