clang API Documentation
00001 //===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines BugReporter, a utility class for generating 00011 // PathDiagnostics for analyses based on ProgramState. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #ifndef LLVM_CLANG_GR_BUGREPORTER 00016 #define LLVM_CLANG_GR_BUGREPORTER 00017 00018 #include "clang/Basic/SourceLocation.h" 00019 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" 00020 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 00021 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 00022 #include "llvm/ADT/FoldingSet.h" 00023 #include "llvm/ADT/ilist.h" 00024 #include "llvm/ADT/ilist_node.h" 00025 #include "llvm/ADT/ImmutableSet.h" 00026 #include "llvm/ADT/DenseSet.h" 00027 00028 namespace clang { 00029 00030 class ASTContext; 00031 class DiagnosticsEngine; 00032 class Stmt; 00033 class ParentMap; 00034 00035 namespace ento { 00036 00037 class PathDiagnostic; 00038 class ExplodedNode; 00039 class ExplodedGraph; 00040 class BugReport; 00041 class BugReporter; 00042 class BugReporterContext; 00043 class ExprEngine; 00044 class BugType; 00045 00046 //===----------------------------------------------------------------------===// 00047 // Interface for individual bug reports. 00048 //===----------------------------------------------------------------------===// 00049 00050 /// This class provides an interface through which checkers can create 00051 /// individual bug reports. 00052 class BugReport : public llvm::ilist_node<BugReport> { 00053 public: 00054 class NodeResolver { 00055 virtual void anchor(); 00056 public: 00057 virtual ~NodeResolver() {} 00058 virtual const ExplodedNode* 00059 getOriginalNode(const ExplodedNode *N) = 0; 00060 }; 00061 00062 typedef const SourceRange *ranges_iterator; 00063 typedef SmallVector<BugReporterVisitor *, 8> VisitorList; 00064 typedef VisitorList::iterator visitor_iterator; 00065 typedef SmallVector<StringRef, 2> ExtraTextList; 00066 00067 protected: 00068 friend class BugReporter; 00069 friend class BugReportEquivClass; 00070 00071 BugType& BT; 00072 const Decl *DeclWithIssue; 00073 std::string ShortDescription; 00074 std::string Description; 00075 PathDiagnosticLocation Location; 00076 PathDiagnosticLocation UniqueingLocation; 00077 const ExplodedNode *ErrorNode; 00078 SmallVector<SourceRange, 4> Ranges; 00079 ExtraTextList ExtraText; 00080 00081 typedef llvm::DenseSet<SymbolRef> Symbols; 00082 typedef llvm::DenseSet<const MemRegion *> Regions; 00083 00084 /// A set of symbols that are registered with this report as being 00085 /// "interesting", and thus used to help decide which diagnostics 00086 /// to include when constructing the final path diagnostic. 00087 Symbols interestingSymbols; 00088 00089 /// A set of regions that are registered with this report as being 00090 /// "interesting", and thus used to help decide which diagnostics 00091 /// to include when constructing the final path diagnostic. 00092 Regions interestingRegions; 00093 00094 /// A set of custom visitors which generate "event" diagnostics at 00095 /// interesting points in the path. 00096 VisitorList Callbacks; 00097 00098 /// Used for ensuring the visitors are only added once. 00099 llvm::FoldingSet<BugReporterVisitor> CallbacksSet; 00100 00101 /// Used for clients to tell if the report's configuration has changed 00102 /// since the last time they checked. 00103 unsigned ConfigurationChangeToken; 00104 00105 public: 00106 BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) 00107 : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode), 00108 ConfigurationChangeToken(0) {} 00109 00110 BugReport(BugType& bt, StringRef shortDesc, StringRef desc, 00111 const ExplodedNode *errornode) 00112 : BT(bt), DeclWithIssue(0), ShortDescription(shortDesc), Description(desc), 00113 ErrorNode(errornode), ConfigurationChangeToken(0) {} 00114 00115 BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l) 00116 : BT(bt), DeclWithIssue(0), Description(desc), Location(l), ErrorNode(0), 00117 ConfigurationChangeToken(0) {} 00118 00119 /// \brief Create a BugReport with a custom uniqueing location. 00120 /// 00121 /// The reports that have the same report location, description, bug type, and 00122 /// ranges are uniqued - only one of the equivalent reports will be presented 00123 /// to the user. This method allows to rest the location which should be used 00124 /// for uniquing reports. For example, memory leaks checker, could set this to 00125 /// the allocation site, rather then the location where the bug is reported. 00126 BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode, 00127 PathDiagnosticLocation LocationToUnique) 00128 : BT(bt), DeclWithIssue(0), Description(desc), 00129 UniqueingLocation(LocationToUnique), 00130 ErrorNode(errornode), ConfigurationChangeToken(0) {} 00131 00132 virtual ~BugReport(); 00133 00134 const BugType& getBugType() const { return BT; } 00135 BugType& getBugType() { return BT; } 00136 00137 const ExplodedNode *getErrorNode() const { return ErrorNode; } 00138 00139 const StringRef getDescription() const { return Description; } 00140 00141 const StringRef getShortDescription() const { 00142 return ShortDescription.empty() ? Description : ShortDescription; 00143 } 00144 00145 void markInteresting(SymbolRef sym); 00146 void markInteresting(const MemRegion *R); 00147 void markInteresting(SVal V); 00148 00149 bool isInteresting(SymbolRef sym) const; 00150 bool isInteresting(const MemRegion *R) const; 00151 bool isInteresting(SVal V) const; 00152 00153 unsigned getConfigurationChangeToken() const { 00154 return ConfigurationChangeToken; 00155 } 00156 00157 /// Return the canonical declaration, be it a method or class, where 00158 /// this issue semantically occurred. 00159 const Decl *getDeclWithIssue() const; 00160 00161 /// Specifically set the Decl where an issue occurred. This isn't necessary 00162 /// for BugReports that cover a path as it will be automatically inferred. 00163 void setDeclWithIssue(const Decl *declWithIssue) { 00164 DeclWithIssue = declWithIssue; 00165 } 00166 00167 /// \brief This allows for addition of meta data to the diagnostic. 00168 /// 00169 /// Currently, only the HTMLDiagnosticClient knows how to display it. 00170 void addExtraText(StringRef S) { 00171 ExtraText.push_back(S); 00172 } 00173 00174 virtual const ExtraTextList &getExtraText() { 00175 return ExtraText; 00176 } 00177 00178 /// \brief Return the "definitive" location of the reported bug. 00179 /// 00180 /// While a bug can span an entire path, usually there is a specific 00181 /// location that can be used to identify where the key issue occurred. 00182 /// This location is used by clients rendering diagnostics. 00183 virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const; 00184 00185 const Stmt *getStmt() const; 00186 00187 /// \brief Add a range to a bug report. 00188 /// 00189 /// Ranges are used to highlight regions of interest in the source code. 00190 /// They should be at the same source code line as the BugReport location. 00191 /// By default, the source range of the statement corresponding to the error 00192 /// node will be used; add a single invalid range to specify absence of 00193 /// ranges. 00194 void addRange(SourceRange R) { 00195 assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used " 00196 "to specify that the report does not have a range."); 00197 Ranges.push_back(R); 00198 } 00199 00200 /// \brief Get the SourceRanges associated with the report. 00201 virtual std::pair<ranges_iterator, ranges_iterator> getRanges(); 00202 00203 /// \brief Add custom or predefined bug report visitors to this report. 00204 /// 00205 /// The visitors should be used when the default trace is not sufficient. 00206 /// For example, they allow constructing a more elaborate trace. 00207 /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(), 00208 /// registerFindLastStore(), registerNilReceiverVisitor(), and 00209 /// registerVarDeclsLastStore(). 00210 void addVisitor(BugReporterVisitor *visitor); 00211 00212 /// Iterators through the custom diagnostic visitors. 00213 visitor_iterator visitor_begin() { return Callbacks.begin(); } 00214 visitor_iterator visitor_end() { return Callbacks.end(); } 00215 00216 /// Profile to identify equivalent bug reports for error report coalescing. 00217 /// Reports are uniqued to ensure that we do not emit multiple diagnostics 00218 /// for each bug. 00219 virtual void Profile(llvm::FoldingSetNodeID& hash) const; 00220 }; 00221 00222 } // end ento namespace 00223 } // end clang namespace 00224 00225 namespace llvm { 00226 template<> struct ilist_traits<clang::ento::BugReport> 00227 : public ilist_default_traits<clang::ento::BugReport> { 00228 clang::ento::BugReport *createSentinel() const { 00229 return static_cast<clang::ento::BugReport *>(&Sentinel); 00230 } 00231 void destroySentinel(clang::ento::BugReport *) const {} 00232 00233 clang::ento::BugReport *provideInitialHead() const { 00234 return createSentinel(); 00235 } 00236 clang::ento::BugReport *ensureHead(clang::ento::BugReport *) const { 00237 return createSentinel(); 00238 } 00239 private: 00240 mutable ilist_half_node<clang::ento::BugReport> Sentinel; 00241 }; 00242 } 00243 00244 namespace clang { 00245 namespace ento { 00246 00247 //===----------------------------------------------------------------------===// 00248 // BugTypes (collections of related reports). 00249 //===----------------------------------------------------------------------===// 00250 00251 class BugReportEquivClass : public llvm::FoldingSetNode { 00252 /// List of *owned* BugReport objects. 00253 llvm::ilist<BugReport> Reports; 00254 00255 friend class BugReporter; 00256 void AddReport(BugReport* R) { Reports.push_back(R); } 00257 public: 00258 BugReportEquivClass(BugReport* R) { Reports.push_back(R); } 00259 ~BugReportEquivClass(); 00260 00261 void Profile(llvm::FoldingSetNodeID& ID) const { 00262 assert(!Reports.empty()); 00263 Reports.front().Profile(ID); 00264 } 00265 00266 typedef llvm::ilist<BugReport>::iterator iterator; 00267 typedef llvm::ilist<BugReport>::const_iterator const_iterator; 00268 00269 iterator begin() { return Reports.begin(); } 00270 iterator end() { return Reports.end(); } 00271 00272 const_iterator begin() const { return Reports.begin(); } 00273 const_iterator end() const { return Reports.end(); } 00274 }; 00275 00276 //===----------------------------------------------------------------------===// 00277 // BugReporter and friends. 00278 //===----------------------------------------------------------------------===// 00279 00280 class BugReporterData { 00281 public: 00282 virtual ~BugReporterData(); 00283 virtual DiagnosticsEngine& getDiagnostic() = 0; 00284 virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0; 00285 virtual ASTContext &getASTContext() = 0; 00286 virtual SourceManager& getSourceManager() = 0; 00287 }; 00288 00289 /// BugReporter is a utility class for generating PathDiagnostics for analysis. 00290 /// It collects the BugReports and BugTypes and knows how to generate 00291 /// and flush the corresponding diagnostics. 00292 class BugReporter { 00293 public: 00294 enum Kind { BaseBRKind, GRBugReporterKind }; 00295 00296 private: 00297 typedef llvm::ImmutableSet<BugType*> BugTypesTy; 00298 BugTypesTy::Factory F; 00299 BugTypesTy BugTypes; 00300 00301 const Kind kind; 00302 BugReporterData& D; 00303 00304 /// Generate and flush the diagnostics for the given bug report. 00305 void FlushReport(BugReportEquivClass& EQ); 00306 00307 /// The set of bug reports tracked by the BugReporter. 00308 llvm::FoldingSet<BugReportEquivClass> EQClasses; 00309 /// A vector of BugReports for tracking the allocated pointers and cleanup. 00310 std::vector<BugReportEquivClass *> EQClassesVector; 00311 00312 protected: 00313 BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), 00314 D(d) {} 00315 00316 public: 00317 BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind), 00318 D(d) {} 00319 virtual ~BugReporter(); 00320 00321 /// \brief Generate and flush diagnostics for all bug reports. 00322 void FlushReports(); 00323 00324 Kind getKind() const { return kind; } 00325 00326 DiagnosticsEngine& getDiagnostic() { 00327 return D.getDiagnostic(); 00328 } 00329 00330 PathDiagnosticConsumer* getPathDiagnosticConsumer() { 00331 return D.getPathDiagnosticConsumer(); 00332 } 00333 00334 /// \brief Iterator over the set of BugTypes tracked by the BugReporter. 00335 typedef BugTypesTy::iterator iterator; 00336 iterator begin() { return BugTypes.begin(); } 00337 iterator end() { return BugTypes.end(); } 00338 00339 /// \brief Iterator over the set of BugReports tracked by the BugReporter. 00340 typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator; 00341 EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } 00342 EQClasses_iterator EQClasses_end() { return EQClasses.end(); } 00343 00344 ASTContext &getContext() { return D.getASTContext(); } 00345 00346 SourceManager& getSourceManager() { return D.getSourceManager(); } 00347 00348 virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic, 00349 SmallVectorImpl<BugReport *> &bugReports) {} 00350 00351 void Register(BugType *BT); 00352 00353 /// \brief Add the given report to the set of reports tracked by BugReporter. 00354 /// 00355 /// The reports are usually generated by the checkers. Further, they are 00356 /// folded based on the profile value, which is done to coalesce similar 00357 /// reports. 00358 void EmitReport(BugReport *R); 00359 00360 void EmitBasicReport(const Decl *DeclWithIssue, 00361 StringRef BugName, StringRef BugCategory, 00362 StringRef BugStr, PathDiagnosticLocation Loc, 00363 SourceRange* RangeBeg, unsigned NumRanges); 00364 00365 void EmitBasicReport(const Decl *DeclWithIssue, 00366 StringRef BugName, StringRef BugCategory, 00367 StringRef BugStr, PathDiagnosticLocation Loc) { 00368 EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0); 00369 } 00370 00371 void EmitBasicReport(const Decl *DeclWithIssue, 00372 StringRef BugName, StringRef Category, 00373 StringRef BugStr, PathDiagnosticLocation Loc, 00374 SourceRange R) { 00375 EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1); 00376 } 00377 00378 static bool classof(const BugReporter* R) { return true; } 00379 00380 private: 00381 llvm::StringMap<BugType *> StrBugTypes; 00382 00383 /// \brief Returns a BugType that is associated with the given name and 00384 /// category. 00385 BugType *getBugTypeForName(StringRef name, StringRef category); 00386 }; 00387 00388 // FIXME: Get rid of GRBugReporter. It's the wrong abstraction. 00389 class GRBugReporter : public BugReporter { 00390 ExprEngine& Eng; 00391 public: 00392 GRBugReporter(BugReporterData& d, ExprEngine& eng) 00393 : BugReporter(d, GRBugReporterKind), Eng(eng) {} 00394 00395 virtual ~GRBugReporter(); 00396 00397 /// getEngine - Return the analysis engine used to analyze a given 00398 /// function or method. 00399 ExprEngine &getEngine() { return Eng; } 00400 00401 /// getGraph - Get the exploded graph created by the analysis engine 00402 /// for the analyzed method or function. 00403 ExplodedGraph &getGraph(); 00404 00405 /// getStateManager - Return the state manager used by the analysis 00406 /// engine. 00407 ProgramStateManager &getStateManager(); 00408 00409 virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, 00410 SmallVectorImpl<BugReport*> &bugReports); 00411 00412 /// classof - Used by isa<>, cast<>, and dyn_cast<>. 00413 static bool classof(const BugReporter* R) { 00414 return R->getKind() == GRBugReporterKind; 00415 } 00416 }; 00417 00418 class BugReporterContext { 00419 virtual void anchor(); 00420 GRBugReporter &BR; 00421 public: 00422 BugReporterContext(GRBugReporter& br) : BR(br) {} 00423 00424 virtual ~BugReporterContext() {} 00425 00426 GRBugReporter& getBugReporter() { return BR; } 00427 00428 ExplodedGraph &getGraph() { return BR.getGraph(); } 00429 00430 ProgramStateManager& getStateManager() { 00431 return BR.getStateManager(); 00432 } 00433 00434 SValBuilder& getSValBuilder() { 00435 return getStateManager().getSValBuilder(); 00436 } 00437 00438 ASTContext &getASTContext() { 00439 return BR.getContext(); 00440 } 00441 00442 SourceManager& getSourceManager() { 00443 return BR.getSourceManager(); 00444 } 00445 00446 virtual BugReport::NodeResolver& getNodeResolver() = 0; 00447 }; 00448 00449 } // end GR namespace 00450 00451 } // end clang namespace 00452 00453 #endif