From: Argyrios Kyrtzidis Date: Thu, 17 Feb 2011 21:39:24 +0000 (+0000) Subject: [analyzer] X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9fb9474c5b267400d4abfbff63c8b39f378235d4;p=clang [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/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index f2a66e3ce9..0fb2dfe36a 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -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">, diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def index 9ffc122a92..9e9d6f8c5a 100644 --- a/include/clang/Frontend/Analyses.def +++ b/include/clang/Frontend/Analyses.def @@ -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) diff --git a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h index 5042729e55..5e5756c4d2 100644 --- a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h +++ b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h @@ -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); diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 0cd10de547..1efc1ae352 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -15,24 +15,91 @@ #define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" +#include 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 + void registerChecker() { + CHECKER *checker = new CHECKER(); + Checkers.push_back(std::make_pair(checker, destruct)); + 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 Funcs; + template + static void destruct(void *obj) { delete static_cast(obj); } + + std::vector Funcs; + + struct DeclCheckerInfo { + CheckerRef Checker; + CheckDeclFunc CheckFn; + HandlesDeclFunc IsForDeclFn; + }; + std::vector DeclCheckers; + + std::vector > BodyCheckers; + + typedef void (*Dtor)(void *); + std::vector > Checkers; + + typedef llvm::SmallVector, 4> + CachedDeclCheckers; + typedef llvm::DenseMap 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 index 0000000000..8c96866f1c --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/CheckerV2.h @@ -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 +class ASTDecl { + template + static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkASTDecl(llvm::cast(D), mgr, BR); + } + + static bool _handlesDecl(const Decl *D) { + return llvm::isa(D); + } +public: + template + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForDecl(checker, _checkDecl, _handlesDecl); + } +}; + +class ASTCodeBody { + template + static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR); + } + +public: + template + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBody(checker, _checkBody); + } +}; + +} // end check namespace + +template +class CheckerV2 { +public: + template + 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 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, 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, + 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 #include "llvm/ADT/StringRef.h" @@ -210,10 +212,10 @@ static bool IsPartOfAST(const CXXRecordDecl *R) { namespace { class ASTFieldVisitor { llvm::SmallVector 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(D)) - if (R->isDefinition()) - CheckASTMemory(R, BR); +namespace { +class LLVMConventionsChecker : public CheckerV2< + check::ASTDecl, + 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(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(); } - 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(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(D), WL); + BugReporter BR(*Mgr); + for (llvm::SmallVectorImpl::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::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)