]> granicus.if.org Git - clang/commitdiff
[analyzer]
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 17 Feb 2011 21:39:24 +0000 (21:39 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 17 Feb 2011 21:39:24 +0000 (21:39 +0000)
-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

include/clang/Driver/CC1Options.td
include/clang/Frontend/Analyses.def
include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
include/clang/StaticAnalyzer/Core/CheckerManager.h
include/clang/StaticAnalyzer/Core/CheckerV2.h [new file with mode: 0644]
lib/StaticAnalyzer/Checkers/Checkers.td
lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
lib/StaticAnalyzer/Core/CheckerManager.cpp
lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp

index f2a66e3ce9f1fcccc63154469742b205a3c3f25d..0fb2dfe36adda83e9577bc844f9f4b991779e8fe 100644 (file)
@@ -48,8 +48,6 @@ def analysis_CFGAddInitializers : Flag<"-cfg-add-initializers">,
   HelpText<"Add C++ initializers to CFGs for all analyses">;
 def analysis_DisplayLiveVariables : Flag<"-dump-live-variables">,
   HelpText<"Print results of live variable analysis">;
-def analysis_LLVMConventionChecker : Flag<"-analyzer-check-llvm-conventions">,
-  HelpText<"Check code for LLVM codebase conventions (domain-specific)">;
 def analysis_SecuritySyntacticChecks : Flag<"-analyzer-check-security-syntactic">,
   HelpText<"Perform quick security checks that require no data flow">;
 def analysis_WarnDeadStores : Flag<"-analyzer-check-dead-stores">,
index 9ffc122a92fa79cf0711517f57556ab5ea351bdb..9e9d6f8c5a32a37a9ead76489758d9e2b920530c 100644 (file)
@@ -27,10 +27,6 @@ ANALYSIS(DisplayLiveVariables, "dump-live-variables",
 ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic",
          "Perform quick security checks that require no data flow", Code)
 
-ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions",
-         "Check code for LLVM codebase conventions (domain-specific)", 
-         TranslationUnit)
-
 ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores",
          "Warn about stores to dead variables", Code)
 
index 5042729e552bb6a8e7a9e8fe559f820f2ca1813e..5e5756c4d2b4d0bfc5361277809a6c68b897d406 100644 (file)
@@ -53,7 +53,6 @@ void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR);
 void RegisterExperimentalChecks(ExprEngine &Eng);
 void RegisterExperimentalInternalChecks(ExprEngine &Eng);
 
-void CheckLLVMConventions(TranslationUnitDecl &TU, BugReporter &BR);
 void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR);
 void CheckSizeofPointer(const Decl *D, BugReporter &BR);
 
index 0cd10de5473478a167a6e7839a8553fd0a530e2c..1efc1ae352c6d9ff2ac79635eff157adb316a814 100644 (file)
 #define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
 
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include <vector>
 
 namespace clang {
+  class Decl;
 
 namespace ento {
   class ExprEngine;
+  class AnalysisManager;
+  class BugReporter;
 
 class CheckerManager {
 public:
-  typedef void (*RegisterToEngFunc)(ExprEngine &Eng);
+  ~CheckerManager();
+
+  typedef void *CheckerRef;
+
+//===----------------------------------------------------------------------===//
+// registerChecker
+//===----------------------------------------------------------------------===//
+
+  /// \brief Used to register checkers.
+  template <typename CHECKER>
+  void registerChecker() {
+    CHECKER *checker = new CHECKER();
+    Checkers.push_back(std::make_pair(checker, destruct<CHECKER>));
+    CHECKER::_register(checker, *this);
+  }
 
+  typedef void (*RegisterToEngFunc)(ExprEngine &Eng);
   void addCheckerRegisterFunction(RegisterToEngFunc fn) {
     Funcs.push_back(fn);
   }
+
+//===----------------------------------------------------------------------===//
+// Functions for running checkers.
+//===----------------------------------------------------------------------===//
+
+  /// \brief Run checkers handling Decls.
+  void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
+                            BugReporter &BR);
+
+  /// \brief Run checkers handling Decls containing a Stmt body.
+  void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
+                            BugReporter &BR);
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions.
+//===----------------------------------------------------------------------===//
+
+  // 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 bool (*HandlesDeclFunc)(const Decl *D);
+  void _registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
+                        HandlesDeclFunc isForDeclFn);
+
+  void _registerForBody(CheckerRef checker, CheckDeclFunc checkfn);
   
   void registerCheckersToEngine(ExprEngine &eng);
 
 private:
-  llvm::SmallVector<RegisterToEngFunc, 8> Funcs;
+  template <typename CHECKER>
+  static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); }
+
+  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;
+
+  typedef llvm::SmallVector<std::pair<CheckerRef, CheckDeclFunc>, 4>
+      CachedDeclCheckers;
+  typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy;
+  CachedDeclCheckersMapTy CachedDeclCheckersMap;
 };
 
 } // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Core/CheckerV2.h b/include/clang/StaticAnalyzer/Core/CheckerV2.h
new file mode 100644 (file)
index 0000000..8c96866
--- /dev/null
@@ -0,0 +1,93 @@
+//== CheckerV2.h - Registration mechanism for checkers -----------*- 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 CheckerV2, used to create and register checkers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_CORE_CHECKERV2
+#define LLVM_CLANG_SA_CORE_CHECKERV2
+
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "llvm/Support/Casting.h"
+
+namespace clang {
+namespace ento {
+  class BugReporter;
+
+namespace check {
+
+struct _VoidCheck {
+  static void _register(void *checker, CheckerManager &mgr) { }
+};
+
+template <typename DECL>
+class ASTDecl {
+  template <typename CHECKER>
+  static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr,
+                         BugReporter &BR) {
+    ((const CHECKER *)checker)->checkASTDecl(llvm::cast<DECL>(D), mgr, BR);
+  }
+
+  static bool _handlesDecl(const Decl *D) {
+    return llvm::isa<DECL>(D);
+  }
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForDecl(checker, _checkDecl<CHECKER>, _handlesDecl);
+  }
+};
+
+class ASTCodeBody {
+  template <typename CHECKER>
+  static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr,
+                         BugReporter &BR) {
+    ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForBody(checker, _checkBody<CHECKER>);
+  }
+};
+
+} // end check namespace
+
+template <typename CHECK1, typename CHECK2=check::_VoidCheck,
+          typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck,
+          typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck,
+          typename CHECK7=check::_VoidCheck, typename CHECK8=check::_VoidCheck,
+          typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck,
+          typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck>
+class CheckerV2 {
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    CHECK1::_register(checker, mgr);
+    CHECK2::_register(checker, mgr);
+    CHECK3::_register(checker, mgr);
+    CHECK4::_register(checker, mgr);
+    CHECK5::_register(checker, mgr);
+    CHECK6::_register(checker, mgr);
+    CHECK7::_register(checker, mgr);
+    CHECK8::_register(checker, mgr);
+    CHECK9::_register(checker, mgr);
+    CHECK10::_register(checker, mgr);
+    CHECK11::_register(checker, mgr);
+    CHECK12::_register(checker, mgr);
+  }
+};
+
+} // end ento namespace
+
+} // end clang namespace
+
+#endif
index 5d30894ebe1caa1aaea8d30e25a2fdfa4da49cc7..234c23f298bf5bb6abbe17a507b6cdb584477386 100644 (file)
@@ -24,6 +24,8 @@ def CoreExperimental : Package<"experimental">,
 def UnixExperimental : Package<"experimental">,
   InPackage<Unix>, Hidden;
 
+def LLVM : Package<"llvm">;
+
 //===----------------------------------------------------------------------===//
 // Groups.
 //===----------------------------------------------------------------------===//
@@ -84,6 +86,11 @@ def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
   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.
 //===----------------------------------------------------------------------===//
index 92d0424fbaf00d8f7ad7b9a8ac1c0a2c445ad1aa..9e3adc804f67acd5a6b635bd2fb837bd1fec4aa1 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
-#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 @@ static bool IsPartOfAST(const CXXRecordDecl *R) {
 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 @@ public:
 };
 } // 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 @@ void ASTFieldVisitor::ReportError(QualType T) {
 }
 
 //===----------------------------------------------------------------------===//
-// 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);
+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);
+  }
 
-    if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
-      ScanCodeDecls(DC_child, 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>();
 }
-
index 0dd56e6c1929d63e30eee273d5b9fd13872dd59c..1989b822ae408ac8bcbbae26a3fa3a8286b35e09 100644 (file)
 
 #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() { }
index 9a350966577c8fe36c29540a61067273183c5046..b16e8189938b1e890f04b5f4753345ffdb6d9f20 100644 (file)
@@ -82,7 +82,6 @@ private:
   Actions ObjCMethodActions;
   Actions ObjCImplementationActions;
   Actions CXXMethodActions;
-  TUActions TranslationUnitActions; // Remove this.
 
 public:
   ASTContext* Ctx;
@@ -170,10 +169,6 @@ public:
     CXXMethodActions.push_back(action);
   }
 
-  void addTranslationUnitAction(TUAction action) {
-    TranslationUnitActions.push_back(action);
-  }
-
   void addObjCImplementationAction(CodeAction action) {
     ObjCImplementationActions.push_back(action);
   }
@@ -207,10 +202,12 @@ public:
 //===----------------------------------------------------------------------===//
 
 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::HandleDeclContext(ASTContext &C, DeclContext *dc) {
 }
 
 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 @@ void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) {
   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 @@ static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
   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)