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