CheckerManager.cpp revision 769ce3e93ad35bd9ac28e4d8b8f035ae4fd9a5b5
1//===--- CheckerManager.cpp - Static Analyzer Checker Manager -------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Defines the Static Analyzer Checker Manager. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/StaticAnalyzer/Core/CheckerManager.h" 15#include "clang/StaticAnalyzer/Core/CheckerProvider.h" 16#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 17#include "clang/Analysis/ProgramPoint.h" 18#include "clang/AST/DeclBase.h" 19 20using namespace clang; 21using namespace ento; 22 23//===----------------------------------------------------------------------===// 24// Functions for running checkers for AST traversing.. 25//===----------------------------------------------------------------------===// 26 27void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, 28 BugReporter &BR) { 29 assert(D); 30 31 unsigned DeclKind = D->getKind(); 32 CachedDeclCheckers *checkers = 0; 33 CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); 34 if (CCI != CachedDeclCheckersMap.end()) { 35 checkers = &(CCI->second); 36 } else { 37 // Find the checkers that should run for this Decl and cache them. 38 checkers = &CachedDeclCheckersMap[DeclKind]; 39 for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) { 40 DeclCheckerInfo &info = DeclCheckers[i]; 41 if (info.IsForDeclFn(D)) 42 checkers->push_back(info.CheckFn); 43 } 44 } 45 46 assert(checkers); 47 for (CachedDeclCheckers::iterator 48 I = checkers->begin(), E = checkers->end(); I != E; ++I) 49 (*I)(D, mgr, BR); 50} 51 52void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, 53 BugReporter &BR) { 54 assert(D && D->hasBody()); 55 56 for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) 57 BodyCheckers[i](D, mgr, BR); 58} 59 60//===----------------------------------------------------------------------===// 61// Functions for running checkers for path-sensitive checking. 62//===----------------------------------------------------------------------===// 63 64template <typename CHECK_CTX> 65static void runPathSensitiveCheckers(CHECK_CTX checkCtx, 66 ExplodedNodeSet &Dst, 67 ExplodedNodeSet &Src) { 68 69 if (checkCtx.Checkers.empty()) { 70 Dst.insert(Src); 71 return; 72 } 73 74 ExplodedNodeSet Tmp; 75 ExplodedNodeSet *PrevSet = &Src; 76 77 for (typename CHECK_CTX::CheckersTy::const_iterator 78 I= checkCtx.Checkers.begin(), E= checkCtx.Checkers.end(); I!=E; ++I) { 79 ExplodedNodeSet *CurrSet = 0; 80 if (I+1 == E) 81 CurrSet = &Dst; 82 else { 83 CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; 84 CurrSet->clear(); 85 } 86 87 for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); 88 NI != NE; ++NI) 89 checkCtx.runChecker(*I, *CurrSet, *NI); 90 91 // Update which NodeSet is the current one. 92 PrevSet = CurrSet; 93 } 94} 95 96namespace { 97 struct CheckStmtContext { 98 typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; 99 bool IsPreVisit; 100 const CheckersTy &Checkers; 101 const Stmt *S; 102 ExprEngine &Eng; 103 104 CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, 105 const Stmt *s, ExprEngine &eng) 106 : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { } 107 108 void runChecker(CheckerManager::CheckStmtFunc checkFn, 109 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 110 // FIXME: Remove respondsToCallback from CheckerContext; 111 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 112 IsPreVisit ? ProgramPoint::PreStmtKind : 113 ProgramPoint::PostStmtKind, 0, S); 114 checkFn(S, C); 115 } 116 }; 117} 118 119/// \brief Run checkers for visiting Stmts. 120void CheckerManager::runCheckersForStmt(bool isPreVisit, 121 ExplodedNodeSet &Dst, 122 ExplodedNodeSet &Src, 123 const Stmt *S, 124 ExprEngine &Eng) { 125 CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit), 126 S, Eng); 127 runPathSensitiveCheckers(C, Dst, Src); 128} 129 130namespace { 131 struct CheckObjCMessageContext { 132 typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy; 133 bool IsPreVisit; 134 const CheckersTy &Checkers; 135 const ObjCMessage &Msg; 136 ExprEngine &Eng; 137 138 CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers, 139 const ObjCMessage &msg, ExprEngine &eng) 140 : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { } 141 142 void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, 143 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 144 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 145 IsPreVisit ? ProgramPoint::PreStmtKind : 146 ProgramPoint::PostStmtKind, 0, 147 Msg.getOriginExpr()); 148 checkFn(Msg, C); 149 } 150 }; 151} 152 153/// \brief Run checkers for visiting obj-c messages. 154void CheckerManager::runCheckersForObjCMessage(bool isPreVisit, 155 ExplodedNodeSet &Dst, 156 ExplodedNodeSet &Src, 157 const ObjCMessage &msg, 158 ExprEngine &Eng) { 159 CheckObjCMessageContext C(isPreVisit, PostObjCMessageCheckers, msg, Eng); 160 runPathSensitiveCheckers(C, Dst, Src); 161} 162 163namespace { 164 struct CheckLocationContext { 165 typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy; 166 const CheckersTy &Checkers; 167 SVal Loc; 168 bool IsLoad; 169 const Stmt *S; 170 const GRState *State; 171 ExprEngine &Eng; 172 173 CheckLocationContext(const CheckersTy &checkers, 174 SVal loc, bool isLoad, const Stmt *s, 175 const GRState *state, ExprEngine &eng) 176 : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), 177 State(state), Eng(eng) { } 178 179 void runChecker(CheckerManager::CheckLocationFunc checkFn, 180 ExplodedNodeSet &Dst, ExplodedNode *Pred) { 181 CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, 182 IsLoad ? ProgramPoint::PreLoadKind : 183 ProgramPoint::PreStoreKind, 0, S, State); 184 checkFn(Loc, IsLoad, C); 185 } 186 }; 187} 188 189/// \brief Run checkers for load/store of a location. 190void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, 191 ExplodedNodeSet &Src, 192 SVal location, bool isLoad, 193 const Stmt *S, 194 const GRState *state, 195 ExprEngine &Eng) { 196 CheckLocationContext C(LocationCheckers, location, isLoad, S, state, Eng); 197 runPathSensitiveCheckers(C, Dst, Src); 198} 199 200void CheckerManager::registerCheckersToEngine(ExprEngine &eng) { 201 for (unsigned i = 0, e = Funcs.size(); i != e; ++i) 202 Funcs[i](eng); 203} 204 205//===----------------------------------------------------------------------===// 206// Internal registration functions for AST traversing. 207//===----------------------------------------------------------------------===// 208 209void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, 210 HandlesDeclFunc isForDeclFn) { 211 DeclCheckerInfo info = { checkfn, isForDeclFn }; 212 DeclCheckers.push_back(info); 213} 214 215void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { 216 BodyCheckers.push_back(checkfn); 217} 218 219//===----------------------------------------------------------------------===// 220// Internal registration functions for path-sensitive checking. 221//===----------------------------------------------------------------------===// 222 223void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, 224 HandlesStmtFunc isForStmtFn) { 225 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; 226 StmtCheckers.push_back(info); 227} 228void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, 229 HandlesStmtFunc isForStmtFn) { 230 StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; 231 StmtCheckers.push_back(info); 232} 233 234void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { 235 PreObjCMessageCheckers.push_back(checkfn); 236} 237void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { 238 PostObjCMessageCheckers.push_back(checkfn); 239} 240 241void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { 242 LocationCheckers.push_back(checkfn); 243} 244 245//===----------------------------------------------------------------------===// 246// Implementation details. 247//===----------------------------------------------------------------------===// 248 249CheckerManager::CachedStmtCheckers * 250CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { 251 assert(S); 252 253 CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit); 254 CachedStmtCheckers *checkers = 0; 255 CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key); 256 if (CCI != CachedStmtCheckersMap.end()) { 257 checkers = &(CCI->second); 258 } else { 259 // Find the checkers that should run for this Stmt and cache them. 260 checkers = &CachedStmtCheckersMap[key]; 261 for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) { 262 StmtCheckerInfo &info = StmtCheckers[i]; 263 if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S)) 264 checkers->push_back(info.CheckFn); 265 } 266 } 267 268 assert(checkers); 269 return checkers; 270} 271 272CheckerManager::~CheckerManager() { 273 for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i) 274 CheckerDtors[i](); 275} 276 277// Anchor for the vtable. 278CheckerProvider::~CheckerProvider() { } 279