BugReporter.h revision 14924267950e75c6c1f6fcea39fa507b7168bc39
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/PathSensitive/ProgramState.h" 21#include "llvm/ADT/FoldingSet.h" 22#include "llvm/ADT/ImmutableList.h" 23#include "llvm/ADT/ImmutableSet.h" 24#include "llvm/ADT/SmallSet.h" 25#include <list> 26 27namespace clang { 28 29class ASTContext; 30class Diagnostic; 31class Stmt; 32class ParentMap; 33 34namespace ento { 35 36class PathDiagnostic; 37class PathDiagnosticPiece; 38class PathDiagnosticClient; 39class ExplodedNode; 40class ExplodedGraph; 41class BugReport; 42class BugReporter; 43class BugReporterContext; 44class ExprEngine; 45class ProgramState; 46class BugType; 47 48//===----------------------------------------------------------------------===// 49// Interface for individual bug reports. 50//===----------------------------------------------------------------------===// 51 52/// This class provides an interface through which checkers can create 53/// individual bug reports. 54class BugReport { 55public: 56 class NodeResolver { 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 FullSourceLoc Location; 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 85 /// Profile to identify equivalent bug reports for error report coalescing. 86 /// Reports are uniqued to ensure that we do not emit multiple diagnostics 87 /// for each bug. 88 virtual void Profile(llvm::FoldingSetNodeID& hash) const; 89 90public: 91 BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) 92 : BT(bt), Description(desc), ErrorNode(errornode), 93 Callbacks(F.getEmptyList()) {} 94 95 BugReport(BugType& bt, StringRef shortDesc, StringRef desc, 96 const ExplodedNode *errornode) 97 : BT(bt), ShortDescription(shortDesc), Description(desc), 98 ErrorNode(errornode), Callbacks(F.getEmptyList()) {} 99 100 BugReport(BugType& bt, StringRef desc, FullSourceLoc l) 101 : BT(bt), Description(desc), Location(l), ErrorNode(0), 102 Callbacks(F.getEmptyList()) {} 103 104 virtual ~BugReport(); 105 106 const BugType& getBugType() const { return BT; } 107 BugType& getBugType() { return BT; } 108 109 const ExplodedNode *getErrorNode() const { return ErrorNode; } 110 111 const StringRef getDescription() const { return Description; } 112 113 const StringRef getShortDescription() const { 114 return ShortDescription.empty() ? Description : ShortDescription; 115 } 116 117 /// \brief This allows for addition of meta data to the diagnostic. 118 /// 119 /// Currently, only the HTMLDiagnosticClient knows how to display it. 120 void addExtraText(StringRef S) { 121 ExtraText.push_back(S); 122 } 123 124 virtual const ExtraTextList &getExtraText() { 125 return ExtraText; 126 } 127 128 /// \brief Return the "definitive" location of the reported bug. 129 /// 130 /// While a bug can span an entire path, usually there is a specific 131 /// location that can be used to identify where the key issue occurred. 132 /// This location is used by clients rendering diagnostics. 133 virtual SourceLocation getLocation() const; 134 135 const Stmt *getStmt() const; 136 137 /// \brief Add a range to a bug report. 138 /// 139 /// Ranges are used to highlight regions of interest in the source code. 140 /// They should be at the same source code line as the BugReport location. 141 /// By default, the source range of the statement corresponding to the error 142 /// node will be used; add a single invalid range to specify absence of 143 /// ranges. 144 void addRange(SourceRange R) { 145 assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used " 146 "to specify that the report does not have a range."); 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 addVisitor(BugReporterVisitor *visitor); 161 162 /// Iterators through the custom diagnostic visitors. 163 visitor_iterator visitor_begin() { return Callbacks.begin(); } 164 visitor_iterator visitor_end() { return Callbacks.end(); } 165}; 166 167//===----------------------------------------------------------------------===// 168// BugTypes (collections of related reports). 169//===----------------------------------------------------------------------===// 170 171class BugReportEquivClass : public llvm::FoldingSetNode { 172 /// List of *owned* BugReport objects. 173 std::list<BugReport*> Reports; 174 175 friend class BugReporter; 176 void AddReport(BugReport* R) { Reports.push_back(R); } 177public: 178 BugReportEquivClass(BugReport* R) { Reports.push_back(R); } 179 ~BugReportEquivClass(); 180 181 void Profile(llvm::FoldingSetNodeID& ID) const { 182 assert(!Reports.empty()); 183 (*Reports.begin())->Profile(ID); 184 } 185 186 class iterator { 187 std::list<BugReport*>::iterator impl; 188 public: 189 iterator(std::list<BugReport*>::iterator i) : impl(i) {} 190 iterator &operator++() { ++impl; return *this; } 191 bool operator==(const iterator &I) const { return I.impl == impl; } 192 bool operator!=(const iterator &I) const { return I.impl != impl; } 193 BugReport* operator*() const { return *impl; } 194 BugReport* operator->() const { return *impl; } 195 }; 196 197 class const_iterator { 198 std::list<BugReport*>::const_iterator impl; 199 public: 200 const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {} 201 const_iterator &operator++() { ++impl; return *this; } 202 bool operator==(const const_iterator &I) const { return I.impl == impl; } 203 bool operator!=(const const_iterator &I) const { return I.impl != impl; } 204 const BugReport* operator*() const { return *impl; } 205 const BugReport* operator->() const { return *impl; } 206 }; 207 208 iterator begin() { return iterator(Reports.begin()); } 209 iterator end() { return iterator(Reports.end()); } 210 211 const_iterator begin() const { return const_iterator(Reports.begin()); } 212 const_iterator end() const { return const_iterator(Reports.end()); } 213}; 214 215//===----------------------------------------------------------------------===// 216// BugReporter and friends. 217//===----------------------------------------------------------------------===// 218 219class BugReporterData { 220public: 221 virtual ~BugReporterData(); 222 virtual Diagnostic& getDiagnostic() = 0; 223 virtual PathDiagnosticClient* getPathDiagnosticClient() = 0; 224 virtual ASTContext &getASTContext() = 0; 225 virtual SourceManager& getSourceManager() = 0; 226}; 227 228/// BugReporter is a utility class for generating PathDiagnostics for analysis. 229/// It collects the BugReports and BugTypes and knows how to generate 230/// and flush the corresponding diagnostics. 231class BugReporter { 232public: 233 enum Kind { BaseBRKind, GRBugReporterKind }; 234 235private: 236 typedef llvm::ImmutableSet<BugType*> BugTypesTy; 237 BugTypesTy::Factory F; 238 BugTypesTy BugTypes; 239 240 const Kind kind; 241 BugReporterData& D; 242 243 /// Generate and flush the diagnostics for the given bug report. 244 void FlushReport(BugReportEquivClass& EQ); 245 246 /// The set of bug reports tracked by the BugReporter. 247 llvm::FoldingSet<BugReportEquivClass> EQClasses; 248 /// A vector of BugReports for tracking the allocated pointers and cleanup. 249 std::vector<BugReportEquivClass *> EQClassesVector; 250 251protected: 252 BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), 253 D(d) {} 254 255public: 256 BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind), 257 D(d) {} 258 virtual ~BugReporter(); 259 260 /// \brief Generate and flush diagnostics for all bug reports. 261 void FlushReports(); 262 263 Kind getKind() const { return kind; } 264 265 Diagnostic& getDiagnostic() { 266 return D.getDiagnostic(); 267 } 268 269 PathDiagnosticClient* getPathDiagnosticClient() { 270 return D.getPathDiagnosticClient(); 271 } 272 273 /// \brief Iterator over the set of BugTypes tracked by the BugReporter. 274 typedef BugTypesTy::iterator iterator; 275 iterator begin() { return BugTypes.begin(); } 276 iterator end() { return BugTypes.end(); } 277 278 /// \brief Iterator over the set of BugReports tracked by the BugReporter. 279 typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator; 280 EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } 281 EQClasses_iterator EQClasses_end() { return EQClasses.end(); } 282 283 ASTContext &getContext() { return D.getASTContext(); } 284 285 SourceManager& getSourceManager() { return D.getSourceManager(); } 286 287 virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic, 288 SmallVectorImpl<BugReport *> &bugReports) {} 289 290 void Register(BugType *BT); 291 292 /// \brief Add the given report to the set of reports tracked by BugReporter. 293 /// 294 /// The reports are usually generated by the checkers. Further, they are 295 /// folded based on the profile value, which is done to coalesce similar 296 /// reports. 297 void EmitReport(BugReport *R); 298 299 void EmitBasicReport(StringRef BugName, StringRef BugStr, 300 SourceLocation Loc, 301 SourceRange* RangeBeg, unsigned NumRanges); 302 303 void EmitBasicReport(StringRef BugName, StringRef BugCategory, 304 StringRef BugStr, SourceLocation Loc, 305 SourceRange* RangeBeg, unsigned NumRanges); 306 307 308 void EmitBasicReport(StringRef BugName, StringRef BugStr, 309 SourceLocation Loc) { 310 EmitBasicReport(BugName, BugStr, Loc, 0, 0); 311 } 312 313 void EmitBasicReport(StringRef BugName, StringRef BugCategory, 314 StringRef BugStr, SourceLocation Loc) { 315 EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); 316 } 317 318 void EmitBasicReport(StringRef BugName, StringRef BugStr, 319 SourceLocation Loc, SourceRange R) { 320 EmitBasicReport(BugName, BugStr, Loc, &R, 1); 321 } 322 323 void EmitBasicReport(StringRef BugName, StringRef Category, 324 StringRef BugStr, SourceLocation Loc, 325 SourceRange R) { 326 EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); 327 } 328 329 static bool classof(const BugReporter* R) { return true; } 330 331private: 332 llvm::StringMap<BugType *> StrBugTypes; 333 334 /// \brief Returns a BugType that is associated with the given name and 335 /// category. 336 BugType *getBugTypeForName(StringRef name, StringRef category); 337}; 338 339// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. 340class GRBugReporter : public BugReporter { 341 ExprEngine& Eng; 342 llvm::SmallSet<SymbolRef, 10> NotableSymbols; 343public: 344 GRBugReporter(BugReporterData& d, ExprEngine& eng) 345 : BugReporter(d, GRBugReporterKind), Eng(eng) {} 346 347 virtual ~GRBugReporter(); 348 349 /// getEngine - Return the analysis engine used to analyze a given 350 /// function or method. 351 ExprEngine &getEngine() { return Eng; } 352 353 /// getGraph - Get the exploded graph created by the analysis engine 354 /// for the analyzed method or function. 355 ExplodedGraph &getGraph(); 356 357 /// getStateManager - Return the state manager used by the analysis 358 /// engine. 359 ProgramStateManager &getStateManager(); 360 361 virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, 362 SmallVectorImpl<BugReport*> &bugReports); 363 364 void addNotableSymbol(SymbolRef Sym) { 365 NotableSymbols.insert(Sym); 366 } 367 368 bool isNotable(SymbolRef Sym) const { 369 return (bool) NotableSymbols.count(Sym); 370 } 371 372 /// classof - Used by isa<>, cast<>, and dyn_cast<>. 373 static bool classof(const BugReporter* R) { 374 return R->getKind() == GRBugReporterKind; 375 } 376}; 377 378class BugReporterContext { 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