aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-02-17 21:39:24 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-02-17 21:39:24 +0000
commit9fb9474c5b267400d4abfbff63c8b39f378235d4 (patch)
treeaedb0a92a4d8d3410af2d57ab21ba224d807f102 /lib
parent695fb502825a53ccd178ec1c85c77929d88acb71 (diff)
[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
Diffstat (limited to 'lib')
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td7
-rw-r--r--lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp48
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp59
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp29
4 files changed, 101 insertions, 42 deletions
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 5d30894ebe..234c23f298 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -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.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index 92d0424fba..9e3adc804f 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 @@ 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>();
}
-
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 0dd56e6c19..1989b822ae 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 9a35096657..b16e818993 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -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)