[analyzer]
-Introduce CheckerV2, a set of templates for convenient declaration & registration of checkers.
 Currently useful just for checkers working on the AST not the path-sensitive ones.
-Enhance CheckerManager to actually collect the checkers and turn it into the entry point for
 running the checkers.
-Use the new mechanism for the LLVMConventionsChecker.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125778 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 5d30894..234c23f 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -24,6 +24,8 @@
 def UnixExperimental : Package<"experimental">,
   InPackage<Unix>, Hidden;
 
+def LLVM : Package<"llvm">;
+
 //===----------------------------------------------------------------------===//
 // Groups.
 //===----------------------------------------------------------------------===//
@@ -84,6 +86,11 @@
   HelpText<"Check for null arguments to CFRetain/CFRelease">,
   DescFile<"BasicObjCFoundationChecks.cpp">;
 
+def LLVMConventionsChecker : Checker<"Conventions">,
+  InPackage<LLVM>,
+  HelpText<"Check code for LLVM codebase conventions">,
+  DescFile<"LLVMConventionsChecker.cpp">;
+
 //===----------------------------------------------------------------------===//
 // Hidden experimental checkers.
 //===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index 92d0424..9e3adc8 100644
--- a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
@@ -12,10 +12,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/StmtVisitor.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
 #include <string>
 #include "llvm/ADT/StringRef.h"
 
@@ -210,10 +212,10 @@
 namespace {
 class ASTFieldVisitor {
   llvm::SmallVector<FieldDecl*, 10> FieldChain;
-  CXXRecordDecl *Root;
+  const CXXRecordDecl *Root;
   BugReporter &BR;
 public:
-  ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
+  ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br)
     : Root(root), BR(br) {}
 
   void Visit(FieldDecl *D);
@@ -221,7 +223,7 @@
 };
 } // end anonymous namespace
 
-static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
+static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR) {
   if (!IsPartOfAST(R))
     return;
 
@@ -283,29 +285,27 @@
 }
 
 //===----------------------------------------------------------------------===//
-// Entry point for all checks.
+// LLVMConventionsChecker
 //===----------------------------------------------------------------------===//
 
-static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
-  for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
-       I!=E ; ++I) {
-
-    Decl *D = *I;
-
-    if (D->hasBody())
-      CheckStringRefAssignedTemporary(D, BR);
-
-    if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
-      if (R->isDefinition())
-        CheckASTMemory(R, BR);
-
-    if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
-      ScanCodeDecls(DC_child, BR);
+namespace {
+class LLVMConventionsChecker : public CheckerV2<
+                                                check::ASTDecl<CXXRecordDecl>,
+                                                check::ASTCodeBody > {
+public:
+  void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr,
+                    BugReporter &BR) const {
+    if (R->isDefinition())
+      CheckASTMemory(R, BR);
   }
+
+  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
+                        BugReporter &BR) const {
+    CheckStringRefAssignedTemporary(D, BR);
+  }
+};
 }
 
-void ento::CheckLLVMConventions(TranslationUnitDecl &TU,
-                                 BugReporter &BR) {
-  ScanCodeDecls(&TU, BR);
+void ento::registerLLVMConventionsChecker(CheckerManager &mgr) {
+  mgr.registerChecker<LLVMConventionsChecker>();
 }
-
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 0dd56e6..1989b82 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -13,14 +13,73 @@
 
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/AST/DeclBase.h"
 
 using namespace clang;
 using namespace ento;
 
+void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
+                                          BugReporter &BR) {
+  assert(D);
+
+  unsigned DeclKind = D->getKind();
+  CachedDeclCheckers *checkers = 0;
+  CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind);
+  if (CCI != CachedDeclCheckersMap.end()) {
+    checkers = &(CCI->second);
+  } else {
+    // Find the checkers that should run for this Decl and cache them.
+    checkers = &CachedDeclCheckersMap[DeclKind];
+    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));
+    }
+  }
+
+  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);
+  }
+}
+
+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);
+  }
+}
+
+void CheckerManager::_registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
+                                      HandlesDeclFunc isForDeclFn) {
+  DeclCheckerInfo info = { checker, checkfn, isForDeclFn };
+  DeclCheckers.push_back(info);
+}
+
+void CheckerManager::_registerForBody(CheckerRef checker,
+                                      CheckDeclFunc checkfn) {
+  BodyCheckers.push_back(std::make_pair(checker, checkfn));
+}
+
 void CheckerManager::registerCheckersToEngine(ExprEngine &eng) {
   for (unsigned i = 0, e = Funcs.size(); i != e; ++i)
     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);
+  }
+}
+
 // Anchor for the vtable.
 CheckerProvider::~CheckerProvider() { }
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 9a35096..b16e818 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -82,7 +82,6 @@
   Actions ObjCMethodActions;
   Actions ObjCImplementationActions;
   Actions CXXMethodActions;
-  TUActions TranslationUnitActions; // Remove this.
 
 public:
   ASTContext* Ctx;
@@ -170,10 +169,6 @@
     CXXMethodActions.push_back(action);
   }
 
-  void addTranslationUnitAction(TUAction action) {
-    TranslationUnitActions.push_back(action);
-  }
-
   void addObjCImplementationAction(CodeAction action) {
     ObjCImplementationActions.push_back(action);
   }
@@ -207,10 +202,12 @@
 //===----------------------------------------------------------------------===//
 
 void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
+  BugReporter BR(*Mgr);
   for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
        I != E; ++I) {
     Decl *D = *I;
-    
+    checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR);
+
     switch (D->getKind()) {
       case Decl::Namespace: {
         HandleDeclContext(C, cast<NamespaceDecl>(D));
@@ -259,14 +256,11 @@
 }
 
 void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+  BugReporter BR(*Mgr);
   TranslationUnitDecl *TU = C.getTranslationUnitDecl();
+  checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
   HandleDeclContext(C, TU);
 
-  for (TUActions::iterator I = TranslationUnitActions.begin(),
-                           E = TranslationUnitActions.end(); I != E; ++I) {
-    (*I)(*this, *Mgr, *TU);
-  }
-
   // Explicitly destroy the PathDiagnosticClient.  This will flush its output.
   // FIXME: This should be replaced with something that doesn't rely on
   // side-effects in PathDiagnosticClient's destructor. This is required when
@@ -308,6 +302,12 @@
   if (D->hasBody() && Opts.AnalyzeNestedBlocks)
     FindBlocks(cast<DeclContext>(D), WL);
 
+  BugReporter BR(*Mgr);
+  for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
+       WI != WE; ++WI)
+    if ((*WI)->hasBody())
+      checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
+
   for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
     for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
          WI != WE; ++WI)
@@ -440,13 +440,6 @@
   CheckSecuritySyntaxOnly(D, BR);
 }
 
-static void ActionLLVMConventionChecker(AnalysisConsumer &C,
-                                        AnalysisManager &mgr,
-                                        TranslationUnitDecl &TU) {
-  BugReporter BR(mgr);
-  CheckLLVMConventions(TU, BR);
-}
-
 static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
                                   Decl *D) {
   if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)