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