[cfe-commits] r126229 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/CheckerManager.h include/clang/StaticAnalyzer/Core/CheckerV2.h include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Checkers/ExprEngine.cpp lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp

Argyrios Kyrtzidis akyrtzi at gmail.com
Tue Feb 22 09:30:38 PST 2011


Author: akirtzidis
Date: Tue Feb 22 11:30:38 2011
New Revision: 126229

URL: http://llvm.org/viewvc/llvm-project?rev=126229&view=rev
Log:
[analyzer] Start moving the path-sensitive checkers to CheckerV2.

-Migrate ObjCSelfInitChecker to CheckerV2. In the process remove the 'preCallSelfFlags' field
 from the checker class and use GRState for storing that info.
-Get ExprEngine to start delegating checker running to CheckerManager.

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=126229&r1=126228&r2=126229&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Tue Feb 22 11:30:38 2011
@@ -16,21 +16,72 @@
 
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
 #include <vector>
 
 namespace clang {
   class Decl;
+  class Stmt;
 
 namespace ento {
   class ExprEngine;
   class AnalysisManager;
   class BugReporter;
+  class CheckerContext;
+  class ObjCMessage;
+  class SVal;
+  class ExplodedNodeSet;
+  class GRState;
+
+struct VoidCheckerFnParm {};
+template <typename P1=VoidCheckerFnParm, typename P2=VoidCheckerFnParm,
+          typename P3=VoidCheckerFnParm, typename P4=VoidCheckerFnParm>
+class CheckerFn {
+  typedef void (*Func)(void *, P1, P2, P3, P4);
+  Func Fn;
+public:
+  void *Checker;
+  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+  void operator()(P1 p1, P2 p2, P3 p3, P4 p4) { Fn(Checker, p1, p2, p3, p4); } 
+};
+
+template <typename P1, typename P2, typename P3>
+class CheckerFn<P1, P2, P3, VoidCheckerFnParm> {
+  typedef void (*Func)(void *, P1, P2, P3);
+  Func Fn;
+public:
+  void *Checker;
+  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+  void operator()(P1 p1, P2 p2, P3 p3) { Fn(Checker, p1, p2, p3); } 
+};
+
+template <typename P1, typename P2>
+class CheckerFn<P1, P2, VoidCheckerFnParm, VoidCheckerFnParm> {
+  typedef void (*Func)(void *, P1, P2);
+  Func Fn;
+public:
+  void *Checker;
+  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+  void operator()(P1 p1, P2 p2) { Fn(Checker, p1, p2); } 
+};
+
+template <>
+class CheckerFn<VoidCheckerFnParm, VoidCheckerFnParm, VoidCheckerFnParm,
+                VoidCheckerFnParm> {
+  typedef void (*Func)(void *);
+  Func Fn;
+public:
+  void *Checker;
+  CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+  void operator()() { Fn(Checker); } 
+};
 
 class CheckerManager {
 public:
   ~CheckerManager();
 
   typedef void *CheckerRef;
+  typedef CheckerFn<> CheckerDtor;
 
 //===----------------------------------------------------------------------===//
 // registerChecker
@@ -40,7 +91,7 @@
   template <typename CHECKER>
   void registerChecker() {
     CHECKER *checker = new CHECKER();
-    Checkers.push_back(std::pair<CheckerRef, Dtor>(checker, destruct<CHECKER>));
+    CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
     CHECKER::_register(checker, *this);
   }
 
@@ -50,7 +101,7 @@
   }
 
 //===----------------------------------------------------------------------===//
-// Functions for running checkers.
+// Functions for running checkers for AST traversing..
 //===----------------------------------------------------------------------===//
 
   /// \brief Run checkers handling Decls.
@@ -62,48 +113,193 @@
                             BugReporter &BR);
 
 //===----------------------------------------------------------------------===//
-// Internal registration functions.
+// Functions for running checkers for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+  /// \brief Run checkers for pre-visiting Stmts.
+  void runCheckersForPreStmt(ExplodedNodeSet &Dst,
+                             ExplodedNodeSet &Src,
+                             const Stmt *S,
+                             ExprEngine &Eng) {
+    runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng);
+  }
+
+  /// \brief Run checkers for post-visiting Stmts.
+  void runCheckersForPostStmt(ExplodedNodeSet &Dst,
+                              ExplodedNodeSet &Src,
+                              const Stmt *S,
+                              ExprEngine &Eng) {
+    runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng);
+  }
+
+  /// \brief Run checkers for visiting Stmts.
+  void runCheckersForStmt(bool isPreVisit,
+                          ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+                          const Stmt *S, ExprEngine &Eng);
+
+  /// \brief Run checkers for pre-visiting obj-c messages.
+  void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
+                                    ExplodedNodeSet &Src,
+                                    const ObjCMessage &msg,
+                                    ExprEngine &Eng) {
+    runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng);
+  }
+
+  /// \brief Run checkers for post-visiting obj-c messages.
+  void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst,
+                                     ExplodedNodeSet &Src,
+                                     const ObjCMessage &msg,
+                                     ExprEngine &Eng) {
+    runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng);
+  }
+
+  /// \brief Run checkers for visiting obj-c messages.
+  void runCheckersForObjCMessage(bool isPreVisit,
+                                 ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+                                 const ObjCMessage &msg, ExprEngine &Eng);
+
+  /// \brief Run checkers for load/store of a location.
+  void runCheckersForLocation(ExplodedNodeSet &Dst,
+                              ExplodedNodeSet &Src,
+                              SVal location, bool isLoad,
+                              const Stmt *S,
+                              const GRState *state,
+                              ExprEngine &Eng);
+
+  // FIXME: Temporary until checker running is moved completely into
+  // CheckerManager.
+  void registerCheckersToEngine(ExprEngine &eng);
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions for AST traversing.
 //===----------------------------------------------------------------------===//
 
   // Functions used by the registration mechanism, checkers should not touch
   // these directly.
 
-  typedef void (*CheckDeclFunc)(CheckerRef checker, const Decl *D,
-                                AnalysisManager& mgr, BugReporter &BR);
+  typedef CheckerFn<const Decl *, AnalysisManager&, BugReporter &>
+      CheckDeclFunc;
+  typedef CheckerFn<const Stmt *, CheckerContext &> CheckStmtFunc;
+
   typedef bool (*HandlesDeclFunc)(const Decl *D);
-  void _registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
-                        HandlesDeclFunc isForDeclFn);
+  void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn);
 
-  void _registerForBody(CheckerRef checker, CheckDeclFunc checkfn);
-  
-  void registerCheckersToEngine(ExprEngine &eng);
+  void _registerForBody(CheckDeclFunc checkfn);
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+  typedef CheckerFn<const ObjCMessage &, CheckerContext &> CheckObjCMessageFunc;
+  typedef CheckerFn<const SVal &/*location*/, bool/*isLoad*/, CheckerContext &>
+      CheckLocationFunc;
+
+  typedef bool (*HandlesStmtFunc)(const Stmt *D);
+  void _registerForPreStmt(CheckStmtFunc checkfn,
+                           HandlesStmtFunc isForStmtFn);
+  void _registerForPostStmt(CheckStmtFunc checkfn,
+                            HandlesStmtFunc isForStmtFn);
+
+  void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn);
+  void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn);
+
+  void _registerForLocation(CheckLocationFunc checkfn);
+
+//===----------------------------------------------------------------------===//
+// Implementation details.
+//===----------------------------------------------------------------------===//
 
 private:
   template <typename CHECKER>
   static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); }
 
+  std::vector<CheckerDtor> CheckerDtors;
+
   std::vector<RegisterToEngFunc> Funcs;
 
   struct DeclCheckerInfo {
-    CheckerRef Checker;
     CheckDeclFunc CheckFn;
     HandlesDeclFunc IsForDeclFn;
   };
   std::vector<DeclCheckerInfo> DeclCheckers;
 
-  std::vector<std::pair<CheckerRef, CheckDeclFunc> > BodyCheckers;
-
-  typedef void (*Dtor)(void *);
-  std::vector<std::pair<CheckerRef, Dtor> > Checkers;
+  std::vector<CheckDeclFunc> BodyCheckers;
 
-  typedef llvm::SmallVector<std::pair<CheckerRef, CheckDeclFunc>, 4>
-      CachedDeclCheckers;
+  typedef llvm::SmallVector<CheckDeclFunc, 4> CachedDeclCheckers;
   typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy;
   CachedDeclCheckersMapTy CachedDeclCheckersMap;
+
+  struct StmtCheckerInfo {
+    CheckStmtFunc CheckFn;
+    HandlesStmtFunc IsForStmtFn;
+    bool IsPreVisit;
+  };
+  std::vector<StmtCheckerInfo> StmtCheckers;
+
+  struct CachedStmtCheckersKey {
+    unsigned StmtKind;
+    bool IsPreVisit;
+
+    CachedStmtCheckersKey() : StmtKind(0), IsPreVisit(0) { }
+    CachedStmtCheckersKey(unsigned stmtKind, bool isPreVisit)
+      : StmtKind(stmtKind), IsPreVisit(isPreVisit) { }
+
+    static CachedStmtCheckersKey getSentinel() {
+      return CachedStmtCheckersKey(~0U, ~0U);
+    }
+    unsigned getHashValue() const {
+      llvm::FoldingSetNodeID ID;
+      ID.AddInteger(StmtKind);
+      ID.AddBoolean(IsPreVisit);
+      return ID.ComputeHash();
+    }
+    bool operator==(const CachedStmtCheckersKey &RHS) const {
+      return StmtKind == RHS.StmtKind && IsPreVisit == RHS.IsPreVisit;
+    }
+  };
+  friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>;
+
+  typedef llvm::SmallVector<CheckStmtFunc, 4> CachedStmtCheckers;
+  typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers>
+      CachedStmtCheckersMapTy;
+  CachedStmtCheckersMapTy CachedStmtCheckersMap;
+
+  CachedStmtCheckers *getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit);
+
+  std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
+  std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
+
+  std::vector<CheckLocationFunc> LocationCheckers;
 };
 
 } // end ento namespace
 
 } // end clang namespace
 
+namespace llvm {
+  /// Define DenseMapInfo so that CachedStmtCheckersKey can be used as key
+  /// in DenseMap and DenseSets.
+  template <>
+  struct DenseMapInfo<clang::ento::CheckerManager::CachedStmtCheckersKey> {
+    static inline clang::ento::CheckerManager::CachedStmtCheckersKey
+        getEmptyKey() {
+      return clang::ento::CheckerManager::CachedStmtCheckersKey();
+    }
+    static inline clang::ento::CheckerManager::CachedStmtCheckersKey
+        getTombstoneKey() {
+      return clang::ento::CheckerManager::CachedStmtCheckersKey::getSentinel();
+    }
+
+    static unsigned
+        getHashValue(clang::ento::CheckerManager::CachedStmtCheckersKey S) {
+      return S.getHashValue();
+    }
+
+    static bool isEqual(clang::ento::CheckerManager::CachedStmtCheckersKey LHS,
+                       clang::ento::CheckerManager::CachedStmtCheckersKey RHS) {
+      return LHS == RHS;
+    }
+  };
+} // end namespace llvm
+
 #endif

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h?rev=126229&r1=126228&r2=126229&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h Tue Feb 22 11:30:38 2011
@@ -41,7 +41,9 @@
 public:
   template <typename CHECKER>
   static void _register(CHECKER *checker, CheckerManager &mgr) {
-    mgr._registerForDecl(checker, _checkDecl<CHECKER>, _handlesDecl);
+    mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker,
+                                                       _checkDecl<CHECKER>),
+                         _handlesDecl);
   }
 };
 
@@ -55,7 +57,91 @@
 public:
   template <typename CHECKER>
   static void _register(CHECKER *checker, CheckerManager &mgr) {
-    mgr._registerForBody(checker, _checkBody<CHECKER>);
+    mgr._registerForBody(CheckerManager::CheckDeclFunc(checker,
+                                                       _checkBody<CHECKER>));
+  }
+};
+
+template <typename STMT>
+class PreStmt {
+  template <typename CHECKER>
+  static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
+    ((const CHECKER *)checker)->checkPreStmt(llvm::cast<STMT>(S), C);
+  }
+
+  static bool _handlesStmt(const Stmt *S) {
+    return llvm::isa<STMT>(S);
+  }
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForPreStmt(CheckerManager::CheckStmtFunc(checker,
+                                                          _checkStmt<CHECKER>),
+                            _handlesStmt);
+  }
+};
+
+template <typename STMT>
+class PostStmt {
+  template <typename CHECKER>
+  static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
+    ((const CHECKER *)checker)->checkPostStmt(llvm::cast<STMT>(S), C);
+  }
+
+  static bool _handlesStmt(const Stmt *S) {
+    return llvm::isa<STMT>(S);
+  }
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForPostStmt(CheckerManager::CheckStmtFunc(checker,
+                                                           _checkStmt<CHECKER>),
+                             _handlesStmt);
+  }
+};
+
+class PreObjCMessage {
+  template <typename CHECKER>
+  static void _checkObjCMessage(void *checker, const ObjCMessage &msg,
+                                CheckerContext &C) {
+    ((const CHECKER *)checker)->checkPreObjCMessage(msg, C);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForPreObjCMessage(
+     CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
+  }
+};
+
+class PostObjCMessage {
+  template <typename CHECKER>
+  static void _checkObjCMessage(void *checker, const ObjCMessage &msg,
+                                CheckerContext &C) {
+    ((const CHECKER *)checker)->checkPostObjCMessage(msg, C);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForPostObjCMessage(
+     CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
+  }
+};
+
+class Location {
+  template <typename CHECKER>
+  static void _checkLocation(void *checker, const SVal &location, bool isLoad,
+                             CheckerContext &C) {
+    ((const CHECKER *)checker)->checkLocation(location, isLoad, C);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForLocation(
+           CheckerManager::CheckLocationFunc(checker, _checkLocation<CHECKER>));
   }
 };
 

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=126229&r1=126228&r2=126229&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Tue Feb 22 11:30:38 2011
@@ -137,6 +137,10 @@
 
   virtual AnalysisManager &getAnalysisManager() { return AMgr; }
 
+  CheckerManager &getCheckerManager() const {
+    return *AMgr.getCheckerManager();
+  }
+
   SValBuilder &getSValBuilder() { return svalBuilder; }
 
   TransferFuncs& getTF() { return *TF; }

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp?rev=126229&r1=126228&r2=126229&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprEngine.cpp Tue Feb 22 11:30:38 2011
@@ -92,12 +92,13 @@
   }
   
   if (CO->empty()) {
-    // If there are no checkers, return early without doing any
-    // more work.
-    Dst.insert(Src);
+    // If there are no checkers, just delegate to the checker manager.
+    getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
+                                           Dst, Src, S, *this);
     return;
   }
 
+  ExplodedNodeSet CheckersV1Dst;
   ExplodedNodeSet Tmp;
   ExplodedNodeSet *PrevSet = &Src;
   unsigned checkersEvaluated = 0;
@@ -108,7 +109,7 @@
       break;
     ExplodedNodeSet *CurrSet = 0;
     if (I+1 == E)
-      CurrSet = &Dst;
+      CurrSet = &CheckersV1Dst;
     else {
       CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
       CurrSet->clear();
@@ -144,6 +145,9 @@
 
   // Don't autotransition.  The CheckerContext objects should do this
   // automatically.
+
+  getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
+                                         Dst, CheckersV1Dst, S, *this);
 }
 
 void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
@@ -152,10 +156,12 @@
                                          bool isPrevisit) {
 
   if (Checkers.empty()) {
-    Dst.insert(Src);
+    getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, Src, msg,
+                                                  *this);
     return;
   }
 
+  ExplodedNodeSet CheckersV1Dst;
   ExplodedNodeSet Tmp;
   ExplodedNodeSet *PrevSet = &Src;
 
@@ -163,7 +169,7 @@
   {
     ExplodedNodeSet *CurrSet = 0;
     if (I+1 == E)
-      CurrSet = &Dst;
+      CurrSet = &CheckersV1Dst;
     else {
       CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
       CurrSet->clear();
@@ -181,8 +187,8 @@
     PrevSet = CurrSet;
   }
 
-  // Don't autotransition.  The CheckerContext objects should do this
-  // automatically.
+  getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, CheckersV1Dst,
+                                                msg, *this);
 }
 
 void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg,
@@ -1923,20 +1929,28 @@
                                 const GRState* state, SVal location,
                                 const void *tag, bool isLoad) {
   // Early checks for performance reason.
-  if (location.isUnknown() || Checkers.empty()) {
+  if (location.isUnknown()) {
     Dst.Add(Pred);
     return;
   }
 
-  ExplodedNodeSet Src, Tmp;
+  ExplodedNodeSet Src;
   Src.Add(Pred);
+  if (Checkers.empty()) {
+    getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
+                                               state, *this);
+    return;
+  }
+
+  ExplodedNodeSet CheckersV1Dst;
+  ExplodedNodeSet Tmp;
   ExplodedNodeSet *PrevSet = &Src;
 
   for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
   {
     ExplodedNodeSet *CurrSet = 0;
     if (I+1 == E)
-      CurrSet = &Dst;
+      CurrSet = &CheckersV1Dst;
     else {
       CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
       CurrSet->clear();
@@ -1957,6 +1971,9 @@
     // Update which NodeSet is the current one.
     PrevSet = CurrSet;
   }
+
+  getCheckerManager().runCheckersForLocation(Dst, CheckersV1Dst, location,
+                                             isLoad, S, state, *this);
 }
 
 bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, 

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp?rev=126229&r1=126228&r2=126229&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp Tue Feb 22 11:30:38 2011
@@ -47,8 +47,9 @@
 // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
 
 #include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
@@ -63,45 +64,23 @@
 static bool isSelfVar(SVal location, CheckerContext &C);
 
 namespace {
-enum SelfFlagEnum {
-  /// \brief No flag set.
-  SelfFlag_None = 0x0,
-  /// \brief Value came from 'self'.
-  SelfFlag_Self    = 0x1,
-  /// \brief Value came from the result of an initializer (e.g. [super init]).
-  SelfFlag_InitRes = 0x2
-};
-}
-
-namespace {
-class ObjCSelfInitChecker : public CheckerVisitor<ObjCSelfInitChecker> {
-  /// \brief A call receiving a reference to 'self' invalidates the object that
-  /// 'self' contains. This field keeps the "self flags" assigned to the 'self'
-  /// object before the call and assign them to the new object that 'self'
-  /// points to after the call.
-  SelfFlagEnum preCallSelfFlags;
-
+class ObjCSelfInitChecker : public CheckerV2<
+                                             check::PostObjCMessage,
+                                             check::PostStmt<ObjCIvarRefExpr>,
+                                             check::PreStmt<ReturnStmt>,
+                                             check::PreStmt<CallExpr>,
+                                             check::PostStmt<CallExpr>,
+                                             check::Location > {
 public:
-  static void *getTag() { static int tag = 0; return &tag; }
-  void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
-  void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E);
-  void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
-  void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE);
-  void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE);
-  virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location,
-                             bool isLoad);
+  void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+  void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
+  void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
+  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+  void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+  void checkLocation(SVal location, bool isLoad, CheckerContext &C) const;
 };
 } // end anonymous namespace
 
-static void RegisterObjCSelfInitChecker(ExprEngine &Eng) {
-  if (Eng.getContext().getLangOptions().ObjC1)
-    Eng.registerCheck(new ObjCSelfInitChecker());
-}
-
-void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
-  mgr.addCheckerRegisterFunction(RegisterObjCSelfInitChecker);
-}
-
 namespace {
 
 class InitSelfBug : public BugType {
@@ -113,22 +92,40 @@
 
 } // end anonymous namespace
 
+namespace {
+enum SelfFlagEnum {
+  /// \brief No flag set.
+  SelfFlag_None = 0x0,
+  /// \brief Value came from 'self'.
+  SelfFlag_Self    = 0x1,
+  /// \brief Value came from the result of an initializer (e.g. [super init]).
+  SelfFlag_InitRes = 0x2
+};
+}
+
 typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag;
 namespace { struct CalledInit {}; }
+namespace { struct PreCallSelfFlags {}; }
 
 namespace clang {
 namespace ento {
   template<>
   struct GRStateTrait<SelfFlag> : public GRStatePartialTrait<SelfFlag> {
-    static void* GDMIndex() {
-      static int index = 0;
-      return &index;
-    }
+    static void* GDMIndex() { static int index = 0; return &index; }
   };
   template <>
   struct GRStateTrait<CalledInit> : public GRStatePartialTrait<bool> {
     static void *GDMIndex() { static int index = 0; return &index; }
   };
+
+  /// \brief A call receiving a reference to 'self' invalidates the object that
+  /// 'self' contains. This keeps the "self flags" assigned to the 'self'
+  /// object before the call so we can assign them to the new object that 'self'
+  /// points to after the call.
+  template <>
+  struct GRStateTrait<PreCallSelfFlags> : public GRStatePartialTrait<unsigned> {
+    static void *GDMIndex() { static int index = 0; return &index; }
+  };
 }
 }
 
@@ -188,8 +185,8 @@
   C.EmitReport(report);
 }
 
-void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
-                                               ObjCMessage msg) {
+void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
+                                               CheckerContext &C) const {
   // When encountering a message that does initialization (init rule),
   // tag the return value so that we know later on that if self has this value
   // then it is properly initialized.
@@ -219,8 +216,8 @@
   // fails.
 }
 
-void ObjCSelfInitChecker::PostVisitObjCIvarRefExpr(CheckerContext &C,
-                                                   const ObjCIvarRefExpr *E) {
+void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
+                                        CheckerContext &C) const {
   // FIXME: A callback should disable checkers at the start of functions.
   if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
                                      C.getCurrentAnalysisContext()->getDecl())))
@@ -231,8 +228,8 @@
                                                  "'[(super or self) init...]'");
 }
 
-void ObjCSelfInitChecker::PreVisitReturnStmt(CheckerContext &C,
-                                             const ReturnStmt *S) {
+void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
+                                       CheckerContext &C) const {
   // FIXME: A callback should disable checkers at the start of functions.
   if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
                                      C.getCurrentAnalysisContext()->getDecl())))
@@ -259,40 +256,46 @@
 // Until we can use inter-procedural analysis, in such a call, transfer the
 // SelfFlags to the result of the call.
 
-void ObjCSelfInitChecker::PreVisitGenericCall(CheckerContext &C,
-                                              const CallExpr *CE) {
+void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
+                                       CheckerContext &C) const {
   const GRState *state = C.getState();
   for (CallExpr::const_arg_iterator
          I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
     SVal argV = state->getSVal(*I);
     if (isSelfVar(argV, C)) {
-      preCallSelfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+      unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+      C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
       return;
     } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
-      preCallSelfFlags = getSelfFlags(argV, C);
+      unsigned selfFlags = getSelfFlags(argV, C);
+      C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
       return;
     }
   }
 }
 
-void ObjCSelfInitChecker::PostVisitGenericCall(CheckerContext &C,
-                                               const CallExpr *CE) {
+void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
+                                        CheckerContext &C) const {
   const GRState *state = C.getState();
   for (CallExpr::const_arg_iterator
          I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
     SVal argV = state->getSVal(*I);
     if (isSelfVar(argV, C)) {
-      addSelfFlag(state, state->getSVal(cast<Loc>(argV)), preCallSelfFlags, C);
+      SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
+      state = state->remove<PreCallSelfFlags>();
+      addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
       return;
     } else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
-      addSelfFlag(state, state->getSVal(CE), preCallSelfFlags, C);
+      SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
+      state = state->remove<PreCallSelfFlags>();
+      addSelfFlag(state, state->getSVal(CE), prevFlags, C);
       return;
     }
   }
 }
 
-void ObjCSelfInitChecker::visitLocation(CheckerContext &C, const Stmt *S,
-                                        SVal location, bool isLoad) {
+void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
+                                        CheckerContext &C) const {
   // Tag the result of a load from 'self' so that we can easily know that the
   // value is the object that 'self' points to.
   const GRState *state = C.getState();
@@ -354,3 +357,11 @@
 static bool isInitMessage(const ObjCMessage &msg) {
   return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule;
 }
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
+  mgr.registerChecker<ObjCSelfInitChecker>();
+}

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=126229&r1=126228&r2=126229&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Tue Feb 22 11:30:38 2011
@@ -13,11 +13,17 @@
 
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/Analysis/ProgramPoint.h"
 #include "clang/AST/DeclBase.h"
 
 using namespace clang;
 using namespace ento;
 
+//===----------------------------------------------------------------------===//
+// Functions for running checkers for AST traversing..
+//===----------------------------------------------------------------------===//
+
 void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
                                           BugReporter &BR) {
   assert(D);
@@ -33,39 +39,162 @@
     for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) {
       DeclCheckerInfo &info = DeclCheckers[i];
       if (info.IsForDeclFn(D))
-        checkers->push_back(std::make_pair(info.Checker, info.CheckFn));
+        checkers->push_back(info.CheckFn);
     }
   }
 
   assert(checkers);
   for (CachedDeclCheckers::iterator
-         I = checkers->begin(), E = checkers->end(); I != E; ++I) {
-    CheckerRef checker = I->first;
-    CheckDeclFunc fn = I->second;
-    fn(checker, D, mgr, BR);
-  }
+         I = checkers->begin(), E = checkers->end(); I != E; ++I)
+    (*I)(D, mgr, BR);
 }
 
 void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
                                           BugReporter &BR) {
   assert(D && D->hasBody());
 
-  for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) {
-    CheckerRef checker = BodyCheckers[i].first;
-    CheckDeclFunc fn = BodyCheckers[i].second;
-    fn(checker, D, mgr, BR);
+  for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i)
+    BodyCheckers[i](D, mgr, BR);
+}
+
+//===----------------------------------------------------------------------===//
+// Functions for running checkers for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+template <typename CHECK_CTX>
+static void runPathSensitiveCheckers(CHECK_CTX checkCtx,
+                                     ExplodedNodeSet &Dst,
+                                     ExplodedNodeSet &Src) {
+
+  if (checkCtx.Checkers.empty()) {
+    Dst.insert(Src);
+    return;
+  }
+
+  ExplodedNodeSet Tmp;
+  ExplodedNodeSet *PrevSet = &Src;
+
+  for (typename CHECK_CTX::CheckersTy::const_iterator
+         I= checkCtx.Checkers.begin(), E= checkCtx.Checkers.end(); I!=E; ++I) {
+    ExplodedNodeSet *CurrSet = 0;
+    if (I+1 == E)
+      CurrSet = &Dst;
+    else {
+      CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+      CurrSet->clear();
+    }
+
+    for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+         NI != NE; ++NI)
+      checkCtx.runChecker(*I, *CurrSet, *NI);
+
+    // Update which NodeSet is the current one.
+    PrevSet = CurrSet;
   }
 }
 
-void CheckerManager::_registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
-                                      HandlesDeclFunc isForDeclFn) {
-  DeclCheckerInfo info = { checker, checkfn, isForDeclFn };
-  DeclCheckers.push_back(info);
+namespace {
+  struct CheckStmtContext {
+    typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;
+    bool IsPreVisit;
+    const CheckersTy &Checkers;
+    const Stmt *S;
+    ExprEngine &Eng;
+
+    CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
+                     const Stmt *s, ExprEngine &eng)
+      : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
+
+    void runChecker(CheckerManager::CheckStmtFunc checkFn,
+                    ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+      // FIXME: Remove respondsToCallback from CheckerContext;
+      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+                       IsPreVisit ? ProgramPoint::PreStmtKind :
+                                    ProgramPoint::PostStmtKind, 0, S);
+      checkFn(S, C);
+    }
+  };
+}
+
+/// \brief Run checkers for visiting Stmts.
+void CheckerManager::runCheckersForStmt(bool isPreVisit,
+                                        ExplodedNodeSet &Dst,
+                                        ExplodedNodeSet &Src,
+                                        const Stmt *S,
+                                        ExprEngine &Eng) {
+  CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
+                     S, Eng);
+  runPathSensitiveCheckers(C, Dst, Src);
+}
+
+namespace {
+  struct CheckObjCMessageContext {
+    typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy;
+    bool IsPreVisit;
+    const CheckersTy &Checkers;
+    const ObjCMessage &Msg;
+    ExprEngine &Eng;
+
+    CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
+                            const ObjCMessage &msg, ExprEngine &eng)
+      : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
+
+    void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
+                    ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+                       IsPreVisit ? ProgramPoint::PreStmtKind :
+                                    ProgramPoint::PostStmtKind, 0,
+                       Msg.getOriginExpr());
+      checkFn(Msg, C);
+    }
+  };
 }
 
-void CheckerManager::_registerForBody(CheckerRef checker,
-                                      CheckDeclFunc checkfn) {
-  BodyCheckers.push_back(std::make_pair(checker, checkfn));
+/// \brief Run checkers for visiting obj-c messages.
+void CheckerManager::runCheckersForObjCMessage(bool isPreVisit,
+                                               ExplodedNodeSet &Dst,
+                                               ExplodedNodeSet &Src,
+                                               const ObjCMessage &msg,
+                                               ExprEngine &Eng) {
+  CheckObjCMessageContext C(isPreVisit, PostObjCMessageCheckers, msg, Eng);
+  runPathSensitiveCheckers(C, Dst, Src);
+}
+
+namespace {
+  struct CheckLocationContext {
+    typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy;
+    const CheckersTy &Checkers;
+    SVal Loc;
+    bool IsLoad;
+    const Stmt *S;
+    const GRState *State;
+    ExprEngine &Eng;
+
+    CheckLocationContext(const CheckersTy &checkers,
+                         SVal loc, bool isLoad, const Stmt *s,
+                         const GRState *state, ExprEngine &eng)
+      : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s),
+        State(state), Eng(eng) { }
+
+    void runChecker(CheckerManager::CheckLocationFunc checkFn,
+                    ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+                       IsLoad ? ProgramPoint::PreLoadKind :
+                       ProgramPoint::PreStoreKind, 0, S, State);
+      checkFn(Loc, IsLoad, C);
+    }
+  };
+}
+
+/// \brief Run checkers for load/store of a location.
+void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
+                                            ExplodedNodeSet &Src,
+                                            SVal location, bool isLoad,
+                                            const Stmt *S,
+                                            const GRState *state,
+                                            ExprEngine &Eng) {
+  CheckLocationContext C(LocationCheckers, location, isLoad, S, state, Eng);
+  runPathSensitiveCheckers(C, Dst, Src);
 }
 
 void CheckerManager::registerCheckersToEngine(ExprEngine &eng) {
@@ -73,12 +202,76 @@
     Funcs[i](eng);
 }
 
-CheckerManager::~CheckerManager() {
-  for (unsigned i = 0, e = Checkers.size(); i != e; ++i) {
-    CheckerRef checker = Checkers[i].first;
-    Dtor dtor = Checkers[i].second;
-    dtor(checker);
+//===----------------------------------------------------------------------===//
+// Internal registration functions for AST traversing.
+//===----------------------------------------------------------------------===//
+
+void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
+                                      HandlesDeclFunc isForDeclFn) {
+  DeclCheckerInfo info = { checkfn, isForDeclFn };
+  DeclCheckers.push_back(info);
+}
+
+void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
+  BodyCheckers.push_back(checkfn);
+}
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
+                                         HandlesStmtFunc isForStmtFn) {
+  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
+  StmtCheckers.push_back(info);
+}
+void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
+                                          HandlesStmtFunc isForStmtFn) {
+  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
+  StmtCheckers.push_back(info);
+}
+
+void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
+  PreObjCMessageCheckers.push_back(checkfn);
+}
+void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
+  PostObjCMessageCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
+  LocationCheckers.push_back(checkfn);
+}
+
+//===----------------------------------------------------------------------===//
+// Implementation details.
+//===----------------------------------------------------------------------===//
+
+CheckerManager::CachedStmtCheckers *
+CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
+  assert(S);
+
+  CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit);
+  CachedStmtCheckers *checkers = 0;
+  CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key);
+  if (CCI != CachedStmtCheckersMap.end()) {
+    checkers = &(CCI->second);
+  } else {
+    // Find the checkers that should run for this Stmt and cache them.
+    checkers = &CachedStmtCheckersMap[key];
+    for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
+      StmtCheckerInfo &info = StmtCheckers[i];
+      if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S))
+        checkers->push_back(info.CheckFn);
+    }
   }
+
+  assert(checkers);
+  return checkers;
+}
+
+CheckerManager::~CheckerManager() {
+  for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
+    CheckerDtors[i]();
 }
 
 // Anchor for the vtable.





More information about the cfe-commits mailing list