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