BugReporter.h revision 3b030a28cda2b953758507769c1d436bec5ec45e
1//===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===// 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// This file defines BugReporter, a utility class for generating 11// PathDiagnostics for analyses based on ProgramState. 12// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_CLANG_GR_BUGREPORTER 16#define LLVM_CLANG_GR_BUGREPORTER 17 18#include "clang/Basic/SourceLocation.h" 19#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 20#include "llvm/ADT/FoldingSet.h" 21#include "llvm/ADT/ImmutableList.h" 22#include "llvm/ADT/ImmutableSet.h" 23#include "llvm/ADT/SmallSet.h" 24#include <list> 25 26namespace clang { 27 28class ASTContext; 29class Diagnostic; 30class Stmt; 31class ParentMap; 32 33namespace ento { 34 35class PathDiagnostic; 36class PathDiagnosticPiece; 37class PathDiagnosticClient; 38class ExplodedNode; 39class ExplodedGraph; 40class BugReport; 41class BugReporter; 42class BugReporterContext; 43class ExprEngine; 44class ProgramState; 45class BugType; 46 47//===----------------------------------------------------------------------===// 48// Interface for individual bug reports. 49//===----------------------------------------------------------------------===// 50 51class BugReporterVisitor : public llvm::FoldingSetNode { 52public: 53 virtual ~BugReporterVisitor(); 54 55 /// \brief Return a diagnostic piece which should be associated with the 56 /// given node. 57 /// 58 /// The last parameter can be used to register a new visitor with the given 59 /// BugReport while processing a node. 60 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 61 const ExplodedNode *PrevN, 62 BugReporterContext &BRC, 63 BugReport &BR) = 0; 64 65 virtual bool isOwnedByReporterContext() { return true; } 66 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; 67}; 68 69/// This class provides an interface through which checkers can create 70/// individual bug reports. 71class BugReport : public BugReporterVisitor { 72public: 73 class NodeResolver { 74 public: 75 virtual ~NodeResolver() {} 76 virtual const ExplodedNode* 77 getOriginalNode(const ExplodedNode *N) = 0; 78 }; 79 80 typedef void (*VisitorCreator)(BugReport &BR, const void *data); 81 typedef const SourceRange *ranges_iterator; 82 typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator; 83 84protected: 85 friend class BugReporter; 86 friend class BugReportEquivClass; 87 typedef SmallVector<std::pair<VisitorCreator, const void*>, 2> Creators; 88 89 BugType& BT; 90 std::string ShortDescription; 91 std::string Description; 92 FullSourceLoc Location; 93 const ExplodedNode *ErrorNode; 94 SmallVector<SourceRange, 4> Ranges; 95 96 // Not the most efficient data structure, but we use an ImmutableList for the 97 // Callbacks because it is safe to make additions to list during iteration. 98 llvm::ImmutableList<BugReporterVisitor*>::Factory F; 99 llvm::ImmutableList<BugReporterVisitor*> Callbacks; 100 llvm::FoldingSet<BugReporterVisitor> CallbacksSet; 101 102 /// Profile to identify equivalent bug reports for error report coalescing. 103 /// Reports are uniqued to ensure that we do not emit multiple diagnostics 104 /// for each bug. 105 virtual void Profile(llvm::FoldingSetNodeID& hash) const; 106 107 const Stmt *getStmt() const; 108 109public: 110 BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) 111 : BT(bt), Description(desc), ErrorNode(errornode), 112 Callbacks(F.getEmptyList()) { 113 addVisitor(this); 114 } 115 116 BugReport(BugType& bt, StringRef shortDesc, StringRef desc, 117 const ExplodedNode *errornode) 118 : BT(bt), ShortDescription(shortDesc), Description(desc), 119 ErrorNode(errornode), Callbacks(F.getEmptyList()) { 120 addVisitor(this); 121 } 122 123 BugReport(BugType& bt, StringRef desc, FullSourceLoc l) 124 : BT(bt), Description(desc), Location(l), ErrorNode(0), 125 Callbacks(F.getEmptyList()) { 126 addVisitor(this); 127 } 128 129 virtual ~BugReport(); 130 131 virtual bool isOwnedByReporterContext() { return false; } 132 133 const BugType& getBugType() const { return BT; } 134 BugType& getBugType() { return BT; } 135 136 const ExplodedNode *getErrorNode() const { return ErrorNode; } 137 138 const StringRef getDescription() const { return Description; } 139 140 const StringRef getShortDescription() const { 141 return ShortDescription.empty() ? Description : ShortDescription; 142 } 143 144 /// \brief This allows for addition of meta data to the diagnostic. 145 /// 146 /// Currently, only the HTMLDiagnosticClient knows how to display it. 147 virtual std::pair<const char**,const char**> getExtraDescriptiveText() { 148 return std::make_pair((const char**)0,(const char**)0); 149 } 150 151 /// Provide custom definition for the last diagnostic piece on the path. 152 virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, 153 const ExplodedNode *N); 154 155 /// \brief Return the "definitive" location of the reported bug. 156 /// 157 /// While a bug can span an entire path, usually there is a specific 158 /// location that can be used to identify where the key issue occurred. 159 /// This location is used by clients rendering diagnostics. 160 virtual SourceLocation getLocation() const; 161 162 /// \brief Add a range to a bug report. 163 /// 164 /// Ranges are used to highlight regions of interest in the source code. 165 /// They should be at the same source code line as the BugReport location. 166 void addRange(SourceRange R) { 167 assert(R.isValid()); 168 Ranges.push_back(R); 169 } 170 171 /// \brief Get the SourceRanges associated with the report. 172 virtual std::pair<ranges_iterator, ranges_iterator> getRanges(); 173 174 /// \brief Add custom or predefined bug report visitors to this report. 175 /// 176 /// The visitors should be used when the default trace is not sufficient. 177 /// For example, they allow constructing a more elaborate trace. 178 /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(), 179 /// registerFindLastStore(), registerNilReceiverVisitor(), and 180 /// registerVarDeclsLastStore(). 181 void addVisitorCreator(VisitorCreator creator, const void *data) { 182 creator(*this, data); 183 } 184 185 void addVisitor(BugReporterVisitor* visitor); 186 187 /// Iterators through the custom diagnostic visitors. 188 visitor_iterator visitor_begin() { return Callbacks.begin(); } 189 visitor_iterator visitor_end() { return Callbacks.end(); } 190 191 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 192 const ExplodedNode *PrevN, 193 BugReporterContext &BRC, 194 BugReport &BR); 195}; 196 197//===----------------------------------------------------------------------===// 198// BugTypes (collections of related reports). 199//===----------------------------------------------------------------------===// 200 201class BugReportEquivClass : public llvm::FoldingSetNode { 202 /// List of *owned* BugReport objects. 203 std::list<BugReport*> Reports; 204 205 friend class BugReporter; 206 void AddReport(BugReport* R) { Reports.push_back(R); } 207public: 208 BugReportEquivClass(BugReport* R) { Reports.push_back(R); } 209 ~BugReportEquivClass(); 210 211 void Profile(llvm::FoldingSetNodeID& ID) const { 212 assert(!Reports.empty()); 213 (*Reports.begin())->Profile(ID); 214 } 215 216 class iterator { 217 std::list<BugReport*>::iterator impl; 218 public: 219 iterator(std::list<BugReport*>::iterator i) : impl(i) {} 220 iterator &operator++() { ++impl; return *this; } 221 bool operator==(const iterator &I) const { return I.impl == impl; } 222 bool operator!=(const iterator &I) const { return I.impl != impl; } 223 BugReport* operator*() const { return *impl; } 224 BugReport* operator->() const { return *impl; } 225 }; 226 227 class const_iterator { 228 std::list<BugReport*>::const_iterator impl; 229 public: 230 const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {} 231 const_iterator &operator++() { ++impl; return *this; } 232 bool operator==(const const_iterator &I) const { return I.impl == impl; } 233 bool operator!=(const const_iterator &I) const { return I.impl != impl; } 234 const BugReport* operator*() const { return *impl; } 235 const BugReport* operator->() const { return *impl; } 236 }; 237 238 iterator begin() { return iterator(Reports.begin()); } 239 iterator end() { return iterator(Reports.end()); } 240 241 const_iterator begin() const { return const_iterator(Reports.begin()); } 242 const_iterator end() const { return const_iterator(Reports.end()); } 243}; 244 245//===----------------------------------------------------------------------===// 246// BugReporter and friends. 247//===----------------------------------------------------------------------===// 248 249class BugReporterData { 250public: 251 virtual ~BugReporterData(); 252 virtual Diagnostic& getDiagnostic() = 0; 253 virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; 254 virtual ASTContext &getASTContext() = 0; 255 virtual SourceManager& getSourceManager() = 0; 256}; 257 258/// BugReporter is a utility class for generating PathDiagnostics for analysis. 259/// It collects the BugReports and BugTypes and knows how to generate 260/// and flush the corresponding diagnostics. 261class BugReporter { 262public: 263 enum Kind { BaseBRKind, GRBugReporterKind }; 264 265private: 266 typedef llvm::ImmutableSet<BugType*> BugTypesTy; 267 BugTypesTy::Factory F; 268 BugTypesTy BugTypes; 269 270 const Kind kind; 271 BugReporterData& D; 272 273 /// Generate and flush the diagnostics for the given bug report. 274 void FlushReport(BugReportEquivClass& EQ); 275 276 /// The set of bug reports tracked by the BugReporter. 277 llvm::FoldingSet<BugReportEquivClass> EQClasses; 278 /// A vector of BugReports for tracking the allocated pointers and cleanup. 279 std::vector<BugReportEquivClass *> EQClassesVector; 280 281protected: 282 BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), 283 D(d) {} 284 285public: 286 BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind), 287 D(d) {} 288 virtual ~BugReporter(); 289 290 /// \brief Generate and flush diagnostics for all bug reports. 291 void FlushReports(); 292 293 Kind getKind() const { return kind; } 294 295 Diagnostic& getDiagnostic() { 296 return D.getDiagnostic(); 297 } 298 299 PathDiagnosticClient* getPathDiagnosticClient() { 300 return D.getPathDiagnosticClient(); 301 } 302 303 /// \brief Iterator over the set of BugTypes tracked by the BugReporter. 304 typedef BugTypesTy::iterator iterator; 305 iterator begin() { return BugTypes.begin(); } 306 iterator end() { return BugTypes.end(); } 307 308 /// \brief Iterator over the set of BugReports tracked by the BugReporter. 309 typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator; 310 EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } 311 EQClasses_iterator EQClasses_end() { return EQClasses.end(); } 312 313 ASTContext &getContext() { return D.getASTContext(); } 314 315 SourceManager& getSourceManager() { return D.getSourceManager(); } 316 317 virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic, 318 SmallVectorImpl<BugReport *> &bugReports) {} 319 320 void Register(BugType *BT); 321 322 /// \brief Add the given report to the set of reports tracked by BugReporter. 323 /// 324 /// The reports are usually generated by the checkers. Further, they are 325 /// folded based on the profile value, which is done to coalesce similar 326 /// reports. 327 void EmitReport(BugReport *R); 328 329 void EmitBasicReport(StringRef BugName, StringRef BugStr, 330 SourceLocation Loc, 331 SourceRange* RangeBeg, unsigned NumRanges); 332 333 void EmitBasicReport(StringRef BugName, StringRef BugCategory, 334 StringRef BugStr, SourceLocation Loc, 335 SourceRange* RangeBeg, unsigned NumRanges); 336 337 338 void EmitBasicReport(StringRef BugName, StringRef BugStr, 339 SourceLocation Loc) { 340 EmitBasicReport(BugName, BugStr, Loc, 0, 0); 341 } 342 343 void EmitBasicReport(StringRef BugName, StringRef BugCategory, 344 StringRef BugStr, SourceLocation Loc) { 345 EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); 346 } 347 348 void EmitBasicReport(StringRef BugName, StringRef BugStr, 349 SourceLocation Loc, SourceRange R) { 350 EmitBasicReport(BugName, BugStr, Loc, &R, 1); 351 } 352 353 void EmitBasicReport(StringRef BugName, StringRef Category, 354 StringRef BugStr, SourceLocation Loc, 355 SourceRange R) { 356 EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); 357 } 358 359 static bool classof(const BugReporter* R) { return true; } 360 361private: 362 llvm::StringMap<BugType *> StrBugTypes; 363 364 /// \brief Returns a BugType that is associated with the given name and 365 /// category. 366 BugType *getBugTypeForName(StringRef name, StringRef category); 367}; 368 369// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. 370class GRBugReporter : public BugReporter { 371 ExprEngine& Eng; 372 llvm::SmallSet<SymbolRef, 10> NotableSymbols; 373public: 374 GRBugReporter(BugReporterData& d, ExprEngine& eng) 375 : BugReporter(d, GRBugReporterKind), Eng(eng) {} 376 377 virtual ~GRBugReporter(); 378 379 /// getEngine - Return the analysis engine used to analyze a given 380 /// function or method. 381 ExprEngine &getEngine() { return Eng; } 382 383 /// getGraph - Get the exploded graph created by the analysis engine 384 /// for the analyzed method or function. 385 ExplodedGraph &getGraph(); 386 387 /// getStateManager - Return the state manager used by the analysis 388 /// engine. 389 ProgramStateManager &getStateManager(); 390 391 virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, 392 SmallVectorImpl<BugReport*> &bugReports); 393 394 void addNotableSymbol(SymbolRef Sym) { 395 NotableSymbols.insert(Sym); 396 } 397 398 bool isNotable(SymbolRef Sym) const { 399 return (bool) NotableSymbols.count(Sym); 400 } 401 402 /// classof - Used by isa<>, cast<>, and dyn_cast<>. 403 static bool classof(const BugReporter* R) { 404 return R->getKind() == GRBugReporterKind; 405 } 406}; 407 408class BugReporterContext { 409 GRBugReporter &BR; 410public: 411 BugReporterContext(GRBugReporter& br) : BR(br) {} 412 413 virtual ~BugReporterContext() {} 414 415 GRBugReporter& getBugReporter() { return BR; } 416 417 ExplodedGraph &getGraph() { return BR.getGraph(); } 418 419 void addNotableSymbol(SymbolRef Sym) { 420 // FIXME: For now forward to GRBugReporter. 421 BR.addNotableSymbol(Sym); 422 } 423 424 bool isNotable(SymbolRef Sym) const { 425 // FIXME: For now forward to GRBugReporter. 426 return BR.isNotable(Sym); 427 } 428 429 ProgramStateManager& getStateManager() { 430 return BR.getStateManager(); 431 } 432 433 SValBuilder& getSValBuilder() { 434 return getStateManager().getSValBuilder(); 435 } 436 437 ASTContext &getASTContext() { 438 return BR.getContext(); 439 } 440 441 SourceManager& getSourceManager() { 442 return BR.getSourceManager(); 443 } 444 445 virtual BugReport::NodeResolver& getNodeResolver() = 0; 446}; 447 448//===----------------------------------------------------------------------===// 449//===----------------------------------------------------------------------===// 450 451namespace bugreporter { 452 453const Stmt *GetDerefExpr(const ExplodedNode *N); 454const Stmt *GetDenomExpr(const ExplodedNode *N); 455const Stmt *GetCalleeExpr(const ExplodedNode *N); 456const Stmt *GetRetValExpr(const ExplodedNode *N); 457 458void registerConditionVisitor(BugReport &BR); 459 460void registerTrackNullOrUndefValue(BugReport &BR, const void *stmt); 461 462void registerFindLastStore(BugReport &BR, const void *memregion); 463 464void registerNilReceiverVisitor(BugReport &BR); 465 466void registerVarDeclsLastStore(BugReport &BR, const void *stmt); 467 468} // end namespace clang::bugreporter 469 470//===----------------------------------------------------------------------===// 471 472} // end GR namespace 473 474} // end clang namespace 475 476#endif 477