[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)