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