diff options
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r-- | include/clang/Analysis/Analyses/Consumed.h | 264 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/FormatString.h | 8 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/ThreadSafety.h | 4 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/UninitializedValues.h | 22 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisContext.h | 6 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Analysis/CFG.h | 90 | ||||
-rw-r--r-- | include/clang/Analysis/CallGraph.h | 4 | ||||
-rw-r--r-- | include/clang/Analysis/FlowSensitive/DataflowSolver.h | 3 | ||||
-rw-r--r-- | include/clang/Analysis/Support/BlkExprDeclBitVector.h | 307 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h | 107 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtVisitor.h | 59 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGStmtVisitor.h | 175 |
13 files changed, 364 insertions, 687 deletions
diff --git a/include/clang/Analysis/Analyses/Consumed.h b/include/clang/Analysis/Analyses/Consumed.h new file mode 100644 index 0000000..23a094a --- /dev/null +++ b/include/clang/Analysis/Analyses/Consumed.h @@ -0,0 +1,264 @@ +//===- Consumed.h ----------------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A intra-procedural analysis for checking consumed properties. This is based, +// in part, on research on linear types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CONSUMED_H +#define LLVM_CLANG_CONSUMED_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/Analyses/PostOrderCFGView.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { +namespace consumed { + + enum ConsumedState { + // No state information for the given variable. + CS_None, + + CS_Unknown, + CS_Unconsumed, + CS_Consumed + }; + + class ConsumedStmtVisitor; + + typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes; + typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag; + typedef std::list<DelayedDiag> DiagList; + + class ConsumedWarningsHandlerBase { + + public: + + virtual ~ConsumedWarningsHandlerBase(); + + /// \brief Emit the warnings and notes left by the analysis. + virtual void emitDiagnostics() {} + + /// \brief Warn that a variable's state doesn't match at the entry and exit + /// of a loop. + /// + /// \param Loc -- The location of the end of the loop. + /// + /// \param VariableName -- The name of the variable that has a mismatched + /// state. + virtual void warnLoopStateMismatch(SourceLocation Loc, + StringRef VariableName) {} + + /// \brief Warn about parameter typestate mismatches upon return. + /// + /// \param Loc -- The SourceLocation of the return statement. + /// + /// \param ExpectedState -- The state the return value was expected to be + /// in. + /// + /// \param ObservedState -- The state the return value was observed to be + /// in. + virtual void warnParamReturnTypestateMismatch(SourceLocation Loc, + StringRef VariableName, + StringRef ExpectedState, + StringRef ObservedState) {}; + + // FIXME: Add documentation. + virtual void warnParamTypestateMismatch(SourceLocation LOC, + StringRef ExpectedState, + StringRef ObservedState) {} + + // FIXME: This can be removed when the attr propagation fix for templated + // classes lands. + /// \brief Warn about return typestates set for unconsumable types. + /// + /// \param Loc -- The location of the attributes. + /// + /// \param TypeName -- The name of the unconsumable type. + virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc, + StringRef TypeName) {} + + /// \brief Warn about return typestate mismatches. + /// + /// \param Loc -- The SourceLocation of the return statement. + /// + /// \param ExpectedState -- The state the return value was expected to be + /// in. + /// + /// \param ObservedState -- The state the return value was observed to be + /// in. + virtual void warnReturnTypestateMismatch(SourceLocation Loc, + StringRef ExpectedState, + StringRef ObservedState) {} + + /// \brief Warn about use-while-consumed errors. + /// \param MethodName -- The name of the method that was incorrectly + /// invoked. + /// + /// \param State -- The state the object was used in. + /// + /// \param Loc -- The SourceLocation of the method invocation. + virtual void warnUseOfTempInInvalidState(StringRef MethodName, + StringRef State, + SourceLocation Loc) {} + + /// \brief Warn about use-while-consumed errors. + /// \param MethodName -- The name of the method that was incorrectly + /// invoked. + /// + /// \param State -- The state the object was used in. + /// + /// \param VariableName -- The name of the variable that holds the unique + /// value. + /// + /// \param Loc -- The SourceLocation of the method invocation. + virtual void warnUseInInvalidState(StringRef MethodName, + StringRef VariableName, + StringRef State, + SourceLocation Loc) {} + }; + + class ConsumedStateMap { + + typedef llvm::DenseMap<const VarDecl *, ConsumedState> VarMapType; + typedef llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState> + TmpMapType; + + protected: + + bool Reachable; + const Stmt *From; + VarMapType VarMap; + TmpMapType TmpMap; + + public: + ConsumedStateMap() : Reachable(true), From(NULL) {} + ConsumedStateMap(const ConsumedStateMap &Other) + : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap), + TmpMap() {} + + /// \brief Warn if any of the parameters being tracked are not in the state + /// they were declared to be in upon return from a function. + void checkParamsForReturnTypestate(SourceLocation BlameLoc, + ConsumedWarningsHandlerBase &WarningsHandler) const; + + /// \brief Clear the TmpMap. + void clearTemporaries(); + + /// \brief Get the consumed state of a given variable. + ConsumedState getState(const VarDecl *Var) const; + + /// \brief Get the consumed state of a given temporary value. + ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const; + + /// \brief Merge this state map with another map. + void intersect(const ConsumedStateMap *Other); + + void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack, + const ConsumedStateMap *LoopBackStates, + ConsumedWarningsHandlerBase &WarningsHandler); + + /// \brief Return true if this block is reachable. + bool isReachable() const { return Reachable; } + + /// \brief Mark the block as unreachable. + void markUnreachable(); + + /// \brief Set the source for a decision about the branching of states. + /// \param Source -- The statement that was the origin of a branching + /// decision. + void setSource(const Stmt *Source) { this->From = Source; } + + /// \brief Set the consumed state of a given variable. + void setState(const VarDecl *Var, ConsumedState State); + + /// \brief Set the consumed state of a given temporary value. + void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State); + + /// \brief Remove the variable from our state map. + void remove(const VarDecl *Var); + + /// \brief Tests to see if there is a mismatch in the states stored in two + /// maps. + /// + /// \param Other -- The second map to compare against. + bool operator!=(const ConsumedStateMap *Other) const; + }; + + class ConsumedBlockInfo { + std::vector<ConsumedStateMap*> StateMapsArray; + std::vector<unsigned int> VisitOrder; + + public: + ConsumedBlockInfo() { } + + ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph) + : StateMapsArray(NumBlocks, 0), VisitOrder(NumBlocks, 0) { + unsigned int VisitOrderCounter = 0; + for (PostOrderCFGView::iterator BI = SortedGraph->begin(), + BE = SortedGraph->end(); BI != BE; ++BI) { + VisitOrder[(*BI)->getBlockID()] = VisitOrderCounter++; + } + } + + bool allBackEdgesVisited(const CFGBlock *CurrBlock, + const CFGBlock *TargetBlock); + + void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap, + bool &AlreadyOwned); + void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap); + + ConsumedStateMap* borrowInfo(const CFGBlock *Block); + + void discardInfo(const CFGBlock *Block); + + ConsumedStateMap* getInfo(const CFGBlock *Block); + + bool isBackEdge(const CFGBlock *From, const CFGBlock *To); + bool isBackEdgeTarget(const CFGBlock *Block); + }; + + /// A class that handles the analysis of uniqueness violations. + class ConsumedAnalyzer { + + ConsumedBlockInfo BlockInfo; + ConsumedStateMap *CurrStates; + + ConsumedState ExpectedReturnState; + + void determineExpectedReturnState(AnalysisDeclContext &AC, + const FunctionDecl *D); + bool hasConsumableAttributes(const CXXRecordDecl *RD); + bool splitState(const CFGBlock *CurrBlock, + const ConsumedStmtVisitor &Visitor); + + public: + + ConsumedWarningsHandlerBase &WarningsHandler; + + ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler) + : WarningsHandler(WarningsHandler) {} + + ConsumedState getExpectedReturnState() const { return ExpectedReturnState; } + + /// \brief Check a function's CFG for consumed violations. + /// + /// We traverse the blocks in the CFG, keeping track of the state of each + /// value who's type has uniquness annotations. If methods are invoked in + /// the wrong state a warning is issued. Each block in the CFG is traversed + /// exactly once. + void run(AnalysisDeclContext &AC); + }; +}} // end namespace clang::consumed + +#endif diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 4bd989c..c9516b5 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -49,7 +49,7 @@ public: const char *toString() const { return representation; } // Overloaded operators for bool like qualities - operator bool() const { return flag; } + LLVM_EXPLICIT operator bool() const { return flag; } OptionalFlag& operator=(const bool &rhs) { flag = rhs; return *this; // Return a reference to myself. @@ -73,6 +73,9 @@ public: AsIntMax, // 'j' AsSizeT, // 'z' AsPtrDiff, // 't' + AsInt32, // 'I32' (MSVCRT, like __int32) + AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL) + AsInt64, // 'I64' (MSVCRT, like __int64) AsLongDouble, // 'L' AsAllocate, // for '%as', GNU extension to C90 scanf AsMAllocate, // for '%ms', GNU extension to scanf @@ -95,6 +98,9 @@ public: case AsLongLong: case AsChar: return 2; + case AsInt32: + case AsInt64: + return 3; case None: return 0; } diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h index 8a888e6..5def3dd 100644 --- a/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/include/clang/Analysis/Analyses/ThreadSafety.h @@ -11,8 +11,8 @@ // A intra-procedural analysis for thread safety (e.g. deadlocks and race // conditions), based off of an annotation system. // -// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more -// information. +// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking +// for more information. // //===----------------------------------------------------------------------===// diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index e8810c3..188722d 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -38,6 +38,12 @@ private: /// The expression which uses this variable. const Expr *User; + /// Is this use uninitialized whenever the function is called? + bool UninitAfterCall; + + /// Is this use uninitialized whenever the variable declaration is reached? + bool UninitAfterDecl; + /// Does this use always see an uninitialized value? bool AlwaysUninit; @@ -46,13 +52,17 @@ private: SmallVector<Branch, 2> UninitBranches; public: - UninitUse(const Expr *User, bool AlwaysUninit) : - User(User), AlwaysUninit(AlwaysUninit) {} + UninitUse(const Expr *User, bool AlwaysUninit) + : User(User), UninitAfterCall(false), UninitAfterDecl(false), + AlwaysUninit(AlwaysUninit) {} void addUninitBranch(Branch B) { UninitBranches.push_back(B); } + void setUninitAfterCall() { UninitAfterCall = true; } + void setUninitAfterDecl() { UninitAfterDecl = true; } + /// Get the expression containing the uninitialized use. const Expr *getUser() const { return User; } @@ -62,6 +72,12 @@ public: Maybe, /// The use is uninitialized whenever a certain branch is taken. Sometimes, + /// The use is uninitialized the first time it is reached after we reach + /// the variable's declaration. + AfterDecl, + /// The use is uninitialized the first time it is reached after the function + /// is called. + AfterCall, /// The use is always uninitialized. Always }; @@ -69,6 +85,8 @@ public: /// Get the kind of uninitialized use. Kind getKind() const { return AlwaysUninit ? Always : + UninitAfterCall ? AfterCall : + UninitAfterDecl ? AfterDecl : !branch_empty() ? Sometimes : Maybe; } diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 46d7d07..b6f183d 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -16,18 +16,14 @@ #define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H #include "clang/AST/Decl.h" -#include "clang/AST/Expr.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/PointerUnion.h" #include "llvm/Support/Allocator.h" namespace clang { -class Decl; class Stmt; class CFGReverseBlockReachabilityAnalysis; class CFGStmtMap; @@ -35,7 +31,6 @@ class LiveVariables; class ManagedAnalysis; class ParentMap; class PseudoConstantAnalysis; -class ImplicitParamDecl; class LocationContextManager; class StackFrameContext; class BlockInvocationContext; @@ -256,6 +251,7 @@ public: virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; + void dumpStack(raw_ostream &OS, StringRef Indent = "") const; LLVM_ATTRIBUTE_USED void dumpStack() const; public: diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index d4e1f5f..33c940e 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) ENUM, + SFINAE,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 ee0be73..14b7ab8 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -43,6 +43,8 @@ namespace clang { class PrinterHelper; class LangOptions; class ASTContext; + class CXXRecordDecl; + class CXXDeleteExpr; /// CFGElement - Represents a top-level expression in a basic block. class CFGElement { @@ -53,6 +55,7 @@ public: Initializer, // dtor kind AutomaticObjectDtor, + DeleteDtor, BaseDtor, MemberDtor, TemporaryDtor, @@ -185,6 +188,31 @@ private: } }; +/// CFGDeleteDtor - Represents C++ object destructor generated +/// from a call to delete. +class CFGDeleteDtor : public CFGImplicitDtor { +public: + CFGDeleteDtor(const CXXRecordDecl *RD, const CXXDeleteExpr *DE) + : CFGImplicitDtor(DeleteDtor, RD, DE) {} + + const CXXRecordDecl *getCXXRecordDecl() const { + return static_cast<CXXRecordDecl*>(Data1.getPointer()); + } + + // Get Delete expression which triggered the destructor call. + const CXXDeleteExpr *getDeleteExpr() const { + return static_cast<CXXDeleteExpr *>(Data2.getPointer()); + } + + +private: + friend class CFGElement; + CFGDeleteDtor() {} + static bool isKind(const CFGElement &elem) { + return elem.getKind() == DeleteDtor; + } +}; + /// CFGBaseDtor - Represents C++ object destructor implicitly generated for /// base object in destructor. class CFGBaseDtor : public CFGImplicitDtor { @@ -269,7 +297,7 @@ public: Stmt &operator*() { return *getStmt(); } const Stmt &operator*() const { return *getStmt(); } - operator bool() const { return getStmt(); } + LLVM_EXPLICIT operator bool() const { return getStmt(); } }; /// CFGBlock - Represents a single basic block in a source-level CFG. @@ -564,6 +592,10 @@ public: Elements.push_back(CFGAutomaticObjDtor(VD, S), C); } + void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) { + Elements.push_back(CFGDeleteDtor(RD, DE), 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. @@ -745,6 +777,35 @@ public: TryDispatchBlocks.push_back(block); } + /// Records a synthetic DeclStmt and the DeclStmt it was constructed from. + /// + /// The CFG uses synthetic DeclStmts when a single AST DeclStmt contains + /// multiple decls. + void addSyntheticDeclStmt(const DeclStmt *Synthetic, + const DeclStmt *Source) { + assert(Synthetic->isSingleDecl() && "Can handle single declarations only"); + assert(Synthetic != Source && "Don't include original DeclStmts in map"); + assert(!SyntheticDeclStmts.count(Synthetic) && "Already in map"); + SyntheticDeclStmts[Synthetic] = Source; + } + + typedef llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator + synthetic_stmt_iterator; + + /// Iterates over synthetic DeclStmts in the CFG. + /// + /// Each element is a (synthetic statement, source statement) pair. + /// + /// \sa addSyntheticDeclStmt + synthetic_stmt_iterator synthetic_stmt_begin() const { + return SyntheticDeclStmts.begin(); + } + + /// \sa synthetic_stmt_begin + synthetic_stmt_iterator synthetic_stmt_end() const { + return SyntheticDeclStmts.end(); + } + //===--------------------------------------------------------------------===// // Member templates useful for various batch operations over CFGs. //===--------------------------------------------------------------------===// @@ -763,21 +824,6 @@ public: // CFG Introspection. //===--------------------------------------------------------------------===// - struct BlkExprNumTy { - const signed Idx; - explicit BlkExprNumTy(signed idx) : Idx(idx) {} - explicit BlkExprNumTy() : Idx(-1) {} - operator bool() const { return Idx >= 0; } - operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; } - }; - - 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(); - /// getNumBlockIDs - Returns the total number of BlockIDs allocated (which /// start at 0). unsigned getNumBlockIDs() const { return NumBlockIDs; } @@ -800,9 +846,7 @@ public: //===--------------------------------------------------------------------===// CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0), - BlkExprMap(NULL), Blocks(BlkBVC, 10) {} - - ~CFG(); + Blocks(BlkBVC, 10) {} llvm::BumpPtrAllocator& getAllocator() { return BlkBVC.getAllocator(); @@ -819,11 +863,6 @@ private: // for indirect gotos unsigned NumBlockIDs; - // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h. - // It represents a map from Expr* to integers to record the set of - // block-level expressions and their "statement number" in the CFG. - void * BlkExprMap; - BumpVectorContext BlkBVC; CFGBlockListTy Blocks; @@ -832,6 +871,9 @@ private: /// This is the collection of such blocks present in the CFG. std::vector<const CFGBlock *> TryDispatchBlocks; + /// Collects DeclStmts synthesized for this CFG and maps each one back to its + /// source DeclStmt. + llvm::DenseMap<const DeclStmt *, const DeclStmt *> SyntheticDeclStmts; }; } // end namespace clang diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h index 5015eb6..593ba57 100644 --- a/include/clang/Analysis/CallGraph.h +++ b/include/clang/Analysis/CallGraph.h @@ -144,8 +144,8 @@ private: public: CallGraphNode(Decl *D) : FD(D) {} - typedef SmallVector<CallRecord, 5>::iterator iterator; - typedef SmallVector<CallRecord, 5>::const_iterator const_iterator; + typedef SmallVectorImpl<CallRecord>::iterator iterator; + typedef SmallVectorImpl<CallRecord>::const_iterator const_iterator; /// Iterators through all the callees/children of the node. inline iterator begin() { return CalledFunctions.begin(); } diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h index 0f5e7bf..c611ea2 100644 --- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h +++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -45,8 +45,7 @@ public: /// dequeue - Remove a block from the worklist. const CFGBlock *dequeue() { assert(!BlockQueue.empty()); - const CFGBlock *B = BlockQueue.back(); - BlockQueue.pop_back(); + const CFGBlock *B = BlockQueue.pop_back_val(); BlockSet[B] = 0; return B; } diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h deleted file mode 100644 index 35cc799..0000000 --- a/include/clang/Analysis/Support/BlkExprDeclBitVector.h +++ /dev/null @@ -1,307 +0,0 @@ -// BlkExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- 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 definition of dataflow types used by analyses such -// as LiveVariables and UninitializedValues. The underlying dataflow values -// are implemented as bitvectors, but the definitions in this file include -// the necessary boilerplate to use with our dataflow framework. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_STMTDECLBVDVAL_H -#define LLVM_CLANG_STMTDECLBVDVAL_H - -#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion -#include "clang/Analysis/CFG.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DenseMap.h" - -namespace clang { - - class Stmt; - class ASTContext; - -struct DeclBitVector_Types { - - class Idx { - unsigned I; - public: - explicit Idx(unsigned i) : I(i) {} - Idx() : I(~0U) {} - - bool isValid() const { - return I != ~0U; - } - operator unsigned() const { - assert (isValid()); - return I; - } - }; - - //===--------------------------------------------------------------------===// - // AnalysisDataTy - Whole-function meta data. - //===--------------------------------------------------------------------===// - - class AnalysisDataTy { - public: - typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy; - typedef DMapTy::const_iterator decl_iterator; - - protected: - DMapTy DMap; - unsigned NDecls; - - public: - - AnalysisDataTy() : NDecls(0) {} - virtual ~AnalysisDataTy() {} - - bool isTracked(const NamedDecl *SD) { return DMap.find(SD) != DMap.end(); } - - Idx getIdx(const NamedDecl *SD) const { - DMapTy::const_iterator I = DMap.find(SD); - return I == DMap.end() ? Idx() : Idx(I->second); - } - - unsigned getNumDecls() const { return NDecls; } - - void Register(const NamedDecl *SD) { - if (!isTracked(SD)) DMap[SD] = NDecls++; - } - - decl_iterator begin_decl() const { return DMap.begin(); } - decl_iterator end_decl() const { return DMap.end(); } - }; - - //===--------------------------------------------------------------------===// - // ValTy - Dataflow value. - //===--------------------------------------------------------------------===// - - class ValTy { - llvm::BitVector DeclBV; - public: - - void resetDeclValues(AnalysisDataTy& AD) { - DeclBV.resize(AD.getNumDecls()); - DeclBV.reset(); - } - - void setDeclValues(AnalysisDataTy& AD) { - DeclBV.resize(AD.getNumDecls()); - DeclBV.set(); - } - - void resetValues(AnalysisDataTy& AD) { - resetDeclValues(AD); - } - - bool operator==(const ValTy& RHS) const { - assert (sizesEqual(RHS)); - return DeclBV == RHS.DeclBV; - } - - void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; } - - llvm::BitVector::reference getBit(unsigned i) { - return DeclBV[i]; - } - - bool getBit(unsigned i) const { - return DeclBV[i]; - } - - llvm::BitVector::reference - operator()(const NamedDecl *ND, const AnalysisDataTy& AD) { - return getBit(AD.getIdx(ND)); - } - - bool operator()(const NamedDecl *ND, const AnalysisDataTy& AD) const { - return getBit(AD.getIdx(ND)); - } - - llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; } - const llvm::BitVector::reference getDeclBit(unsigned i) const { - return const_cast<llvm::BitVector&>(DeclBV)[i]; - } - - ValTy& operator|=(const ValTy& RHS) { - assert (sizesEqual(RHS)); - DeclBV |= RHS.DeclBV; - return *this; - } - - ValTy& operator&=(const ValTy& RHS) { - assert (sizesEqual(RHS)); - DeclBV &= RHS.DeclBV; - return *this; - } - - ValTy& OrDeclBits(const ValTy& RHS) { - return operator|=(RHS); - } - - ValTy& AndDeclBits(const ValTy& RHS) { - return operator&=(RHS); - } - - bool sizesEqual(const ValTy& RHS) const { - return DeclBV.size() == RHS.DeclBV.size(); - } - }; - - //===--------------------------------------------------------------------===// - // Some useful merge operations. - //===--------------------------------------------------------------------===// - - struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; - struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; -}; - - -struct StmtDeclBitVector_Types { - - //===--------------------------------------------------------------------===// - // AnalysisDataTy - Whole-function meta data. - //===--------------------------------------------------------------------===// - - class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy { - ASTContext *ctx; - CFG* cfg; - public: - AnalysisDataTy() : ctx(0), cfg(0) {} - virtual ~AnalysisDataTy() {} - - void setContext(ASTContext &c) { ctx = &c; } - ASTContext &getContext() { - assert(ctx && "ASTContext should not be NULL."); - return *ctx; - } - - void setCFG(CFG& c) { cfg = &c; } - CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; } - - bool isTracked(const Stmt *S) { return cfg->isBlkExpr(S); } - using DeclBitVector_Types::AnalysisDataTy::isTracked; - - unsigned getIdx(const Stmt *S) const { - CFG::BlkExprNumTy I = cfg->getBlkExprNum(S); - assert(I && "Stmtession not tracked for bitvector."); - return I; - } - using DeclBitVector_Types::AnalysisDataTy::getIdx; - - unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); } - }; - - //===--------------------------------------------------------------------===// - // ValTy - Dataflow value. - //===--------------------------------------------------------------------===// - - class ValTy : public DeclBitVector_Types::ValTy { - llvm::BitVector BlkExprBV; - typedef DeclBitVector_Types::ValTy ParentTy; - - static inline ParentTy& ParentRef(ValTy& X) { - return static_cast<ParentTy&>(X); - } - - static inline const ParentTy& ParentRef(const ValTy& X) { - return static_cast<const ParentTy&>(X); - } - - public: - - void resetBlkExprValues(AnalysisDataTy& AD) { - BlkExprBV.resize(AD.getNumBlkExprs()); - BlkExprBV.reset(); - } - - void setBlkExprValues(AnalysisDataTy& AD) { - BlkExprBV.resize(AD.getNumBlkExprs()); - BlkExprBV.set(); - } - - void resetValues(AnalysisDataTy& AD) { - resetDeclValues(AD); - resetBlkExprValues(AD); - } - - void setValues(AnalysisDataTy& AD) { - setDeclValues(AD); - setBlkExprValues(AD); - } - - bool operator==(const ValTy& RHS) const { - return ParentRef(*this) == ParentRef(RHS) - && BlkExprBV == RHS.BlkExprBV; - } - - void copyValues(const ValTy& RHS) { - ParentRef(*this).copyValues(ParentRef(RHS)); - BlkExprBV = RHS.BlkExprBV; - } - - llvm::BitVector::reference - operator()(const Stmt *S, const AnalysisDataTy& AD) { - return BlkExprBV[AD.getIdx(S)]; - } - const llvm::BitVector::reference - operator()(const Stmt *S, const AnalysisDataTy& AD) const { - return const_cast<ValTy&>(*this)(S,AD); - } - - using DeclBitVector_Types::ValTy::operator(); - - - llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; } - const llvm::BitVector::reference getStmtBit(unsigned i) const { - return const_cast<llvm::BitVector&>(BlkExprBV)[i]; - } - - ValTy& OrBlkExprBits(const ValTy& RHS) { - BlkExprBV |= RHS.BlkExprBV; - return *this; - } - - ValTy& AndBlkExprBits(const ValTy& RHS) { - BlkExprBV &= RHS.BlkExprBV; - return *this; - } - - ValTy& operator|=(const ValTy& RHS) { - assert (sizesEqual(RHS)); - ParentRef(*this) |= ParentRef(RHS); - BlkExprBV |= RHS.BlkExprBV; - return *this; - } - - ValTy& operator&=(const ValTy& RHS) { - assert (sizesEqual(RHS)); - ParentRef(*this) &= ParentRef(RHS); - BlkExprBV &= RHS.BlkExprBV; - return *this; - } - - bool sizesEqual(const ValTy& RHS) const { - return ParentRef(*this).sizesEqual(ParentRef(RHS)) - && BlkExprBV.size() == RHS.BlkExprBV.size(); - } - }; - - //===--------------------------------------------------------------------===// - // Some useful merge operations. - //===--------------------------------------------------------------------===// - - struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; - struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; - -}; -} // end namespace clang - -#endif diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h deleted file mode 100644 index 2bf3eda..0000000 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ /dev/null @@ -1,107 +0,0 @@ -//= CFGRecStmtDeclVisitor - Recursive visitor of CFG stmts/decls -*- 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 template class CFGRecStmtDeclVisitor, which extends -// CFGRecStmtVisitor by implementing (typed) visitation of decls. -// -// FIXME: This may not be fully complete. We currently explore only subtypes -// of ScopedDecl. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H -#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H - -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" - -#define DISPATCH_CASE(CLASS) \ -case Decl::CLASS: \ -static_cast<ImplClass*>(this)->Visit##CLASS##Decl( \ - static_cast<CLASS##Decl*>(D)); \ -break; - -#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D) {} -#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D)\ - { static_cast<ImplClass*>(this)->VisitVarDecl(D); } - - -namespace clang { -template <typename ImplClass> -class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> { -public: - - void VisitDeclRefExpr(DeclRefExpr *DR) { - static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl()); - } - - void VisitDeclStmt(DeclStmt *DS) { - for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); - DI != DE; ++DI) { - Decl *D = *DI; - static_cast<ImplClass*>(this)->VisitDecl(D); - // Visit the initializer. - if (VarDecl *VD = dyn_cast<VarDecl>(D)) - if (Expr *I = VD->getInit()) - static_cast<ImplClass*>(this)->Visit(I); - } - } - - void VisitDecl(Decl *D) { - switch (D->getKind()) { - DISPATCH_CASE(Function) - DISPATCH_CASE(CXXMethod) - DISPATCH_CASE(Var) - DISPATCH_CASE(ParmVar) // FIXME: (same) - DISPATCH_CASE(ImplicitParam) - DISPATCH_CASE(EnumConstant) - DISPATCH_CASE(Typedef) - DISPATCH_CASE(TypeAlias) - DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl? - DISPATCH_CASE(CXXRecord) - DISPATCH_CASE(Enum) - DISPATCH_CASE(Field) - DISPATCH_CASE(UsingDirective) - DISPATCH_CASE(Using) - DISPATCH_CASE(NamespaceAlias) - default: - llvm_unreachable("Subtype of ScopedDecl not handled."); - } - } - - DEFAULT_DISPATCH(Var) - DEFAULT_DISPATCH(Function) - DEFAULT_DISPATCH(CXXMethod) - DEFAULT_DISPATCH_VARDECL(ParmVar) - DEFAULT_DISPATCH(ImplicitParam) - DEFAULT_DISPATCH(EnumConstant) - DEFAULT_DISPATCH(Typedef) - DEFAULT_DISPATCH(TypeAlias) - DEFAULT_DISPATCH(Record) - DEFAULT_DISPATCH(Enum) - DEFAULT_DISPATCH(Field) - DEFAULT_DISPATCH(ObjCInterface) - DEFAULT_DISPATCH(ObjCMethod) - DEFAULT_DISPATCH(ObjCProtocol) - DEFAULT_DISPATCH(ObjCCategory) - DEFAULT_DISPATCH(UsingDirective) - DEFAULT_DISPATCH(Using) - DEFAULT_DISPATCH(NamespaceAlias) - - void VisitCXXRecordDecl(CXXRecordDecl *D) { - static_cast<ImplClass*>(this)->VisitRecordDecl(D); - } -}; - -} // end namespace clang - -#undef DISPATCH_CASE -#undef DEFAULT_DISPATCH -#endif diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h deleted file mode 100644 index 4d1cabf..0000000 --- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h +++ /dev/null @@ -1,59 +0,0 @@ -//==- CFGRecStmtVisitor - Recursive visitor of CFG statements ---*- 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 template class CFGRecStmtVisitor, which extends -// CFGStmtVisitor by implementing a default recursive visit of all statements. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H -#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H - -#include "clang/Analysis/Visitors/CFGStmtVisitor.h" - -namespace clang { -template <typename ImplClass> -class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> { -public: - - void VisitStmt(Stmt *S) { - 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; - switch (S->getStmtClass()) { -#define CONDVAR_CASE(CLASS) \ -case Stmt::CLASS ## Class:\ -CondVar = cast<CLASS>(S)->getConditionVariable();\ -break; - CONDVAR_CASE(IfStmt) - CONDVAR_CASE(ForStmt) - CONDVAR_CASE(SwitchStmt) - CONDVAR_CASE(WhileStmt) -#undef CONDVAR_CASE - default: - llvm_unreachable("Infeasible"); - } - static_cast<ImplClass*>(this)->Visit(CondVar->getInit()); - } - - // Defining operator() allows the visitor to be used as a C++ style functor. - void operator()(Stmt *S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);} -}; - -} // end namespace clang - -#endif diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h deleted file mode 100644 index b354ba7..0000000 --- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h +++ /dev/null @@ -1,175 +0,0 @@ -//===--- CFGStmtVisitor.h - Visitor for Stmts in a 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 defines the CFGStmtVisitor interface, which extends -// StmtVisitor. This interface is useful for visiting statements in a CFG -// where some statements have implicit control-flow and thus should -// be treated specially. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H -#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H - -#include "clang/AST/StmtVisitor.h" -#include "clang/Analysis/CFG.h" - -namespace clang { - -#define DISPATCH_CASE(CLASS) \ -case Stmt::CLASS ## Class: return \ -static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); - -#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ -{ return\ - static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\ - cast<Expr>(S)); } - -template <typename ImplClass, typename RetTy=void> -class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { - Stmt *CurrentBlkStmt; - - struct NullifyStmt { - Stmt*& S; - - NullifyStmt(Stmt*& s) : S(s) {} - ~NullifyStmt() { S = NULL; } - }; - -public: - CFGStmtVisitor() : CurrentBlkStmt(NULL) {} - - Stmt *getCurrentBlkStmt() const { return CurrentBlkStmt; } - - RetTy Visit(Stmt *S) { - if (S == CurrentBlkStmt || - !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S)) - return StmtVisitor<ImplClass,RetTy>::Visit(S); - else - return RetTy(); - } - - /// VisitConditionVariableInit - Handle the initialization of condition - /// variables at branches. Valid statements include IfStmt, ForStmt, - /// WhileStmt, and SwitchStmt. - RetTy VisitConditionVariableInit(Stmt *S) { - return RetTy(); - } - - /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in - /// CFGBlocks. Root statements are the statements that appear explicitly in - /// the list of statements in a CFGBlock. For substatements, or when there - /// is no implementation provided for a BlockStmt_XXX method, we default - /// to using StmtVisitor's Visit method. - RetTy BlockStmt_Visit(Stmt *S) { - CurrentBlkStmt = S; - NullifyStmt cleanup(CurrentBlkStmt); - - switch (S->getStmtClass()) { - case Stmt::IfStmtClass: - case Stmt::ForStmtClass: - case Stmt::WhileStmtClass: - case Stmt::SwitchStmtClass: - return static_cast<ImplClass*>(this)->VisitConditionVariableInit(S); - - DISPATCH_CASE(StmtExpr) - DISPATCH_CASE(ConditionalOperator) - DISPATCH_CASE(BinaryConditionalOperator) - DISPATCH_CASE(ObjCForCollectionStmt) - DISPATCH_CASE(CXXForRangeStmt) - - case Stmt::BinaryOperatorClass: { - BinaryOperator* B = cast<BinaryOperator>(S); - if (B->isLogicalOp()) - return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B); - else if (B->getOpcode() == BO_Comma) - return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B); - // Fall through. - } - - default: - if (isa<Expr>(S)) - return - static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S)); - else - return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); - } - } - - 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); - } - - RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt *S) { - return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); - } - - RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr *E) { - return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E); - } - - RetTy BlockStmt_VisitExpr(Expr *E) { - return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E); - } - - RetTy BlockStmt_VisitStmt(Stmt *S) { - return static_cast<ImplClass*>(this)->Visit(S); - } - - RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) { - return - static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); - } - - RetTy BlockStmt_VisitComma(BinaryOperator* B) { - return - static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); - } - - //===--------------------------------------------------------------------===// - // Utility methods. Not called by default (but subclasses may use them). - //===--------------------------------------------------------------------===// - - /// VisitChildren: Call "Visit" on each child of S. - void VisitChildren(Stmt *S) { - - switch (S->getStmtClass()) { - default: - break; - - case Stmt::StmtExprClass: { - CompoundStmt *CS = cast<StmtExpr>(S)->getSubStmt(); - if (CS->body_empty()) return; - static_cast<ImplClass*>(this)->Visit(CS->body_back()); - return; - } - - case Stmt::BinaryOperatorClass: { - BinaryOperator* B = cast<BinaryOperator>(S); - if (B->getOpcode() != BO_Comma) break; - static_cast<ImplClass*>(this)->Visit(B->getRHS()); - return; - } - } - - for (Stmt::child_range I = S->children(); I; ++I) - if (*I) static_cast<ImplClass*>(this)->Visit(*I); - } -}; - -#undef DEFAULT_BLOCKSTMT_VISIT -#undef DISPATCH_CASE - -} // end namespace clang - -#endif |