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