1 //===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines BugReporter, a utility class for generating
11 // PathDiagnostics for analyses based on ProgramState.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_GR_BUGREPORTER
16 #define LLVM_CLANG_GR_BUGREPORTER
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/ilist.h"
24 #include "llvm/ADT/ilist_node.h"
25 #include "llvm/ADT/ImmutableSet.h"
26 #include "llvm/ADT/DenseSet.h"
31 class DiagnosticsEngine;
42 class BugReporterContext;
46 //===----------------------------------------------------------------------===//
47 // Interface for individual bug reports.
48 //===----------------------------------------------------------------------===//
50 /// This class provides an interface through which checkers can create
51 /// individual bug reports.
52 class BugReport : public llvm::ilist_node<BugReport> {
55 virtual void anchor();
57 virtual ~NodeResolver() {}
58 virtual const ExplodedNode*
59 getOriginalNode(const ExplodedNode *N) = 0;
62 typedef const SourceRange *ranges_iterator;
63 typedef SmallVector<BugReporterVisitor *, 8> VisitorList;
64 typedef VisitorList::iterator visitor_iterator;
65 typedef SmallVector<StringRef, 2> ExtraTextList;
68 friend class BugReporter;
69 friend class BugReportEquivClass;
72 const Decl *DeclWithIssue;
73 std::string ShortDescription;
74 std::string Description;
75 PathDiagnosticLocation Location;
76 PathDiagnosticLocation UniqueingLocation;
77 const ExplodedNode *ErrorNode;
78 SmallVector<SourceRange, 4> Ranges;
79 ExtraTextList ExtraText;
81 typedef llvm::DenseSet<SymbolRef> Symbols;
82 typedef llvm::DenseSet<const MemRegion *> Regions;
84 /// A set of symbols that are registered with this report as being
85 /// "interesting", and thus used to help decide which diagnostics
86 /// to include when constructing the final path diagnostic.
87 Symbols interestingSymbols;
89 /// A set of regions that are registered with this report as being
90 /// "interesting", and thus used to help decide which diagnostics
91 /// to include when constructing the final path diagnostic.
92 Regions interestingRegions;
94 /// A set of custom visitors which generate "event" diagnostics at
95 /// interesting points in the path.
96 VisitorList Callbacks;
98 /// Used for ensuring the visitors are only added once.
99 llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
101 /// Used for clients to tell if the report's configuration has changed
102 /// since the last time they checked.
103 unsigned ConfigurationChangeToken;
105 /// When set, this flag disables all callstack pruning from a diagnostic
106 /// path. This is useful for some reports that want maximum fidelty
107 /// when reporting an issue.
111 BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
112 : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode),
113 ConfigurationChangeToken(0), DoNotPrunePath(false) {}
115 BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
116 const ExplodedNode *errornode)
117 : BT(bt), DeclWithIssue(0), ShortDescription(shortDesc), Description(desc),
118 ErrorNode(errornode), ConfigurationChangeToken(0),
119 DoNotPrunePath(false) {}
121 BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l)
122 : BT(bt), DeclWithIssue(0), Description(desc), Location(l), ErrorNode(0),
123 ConfigurationChangeToken(0),
124 DoNotPrunePath(false) {}
126 /// \brief Create a BugReport with a custom uniqueing location.
128 /// The reports that have the same report location, description, bug type, and
129 /// ranges are uniqued - only one of the equivalent reports will be presented
130 /// to the user. This method allows to rest the location which should be used
131 /// for uniquing reports. For example, memory leaks checker, could set this to
132 /// the allocation site, rather then the location where the bug is reported.
133 BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode,
134 PathDiagnosticLocation LocationToUnique)
135 : BT(bt), DeclWithIssue(0), Description(desc),
136 UniqueingLocation(LocationToUnique),
137 ErrorNode(errornode), ConfigurationChangeToken(0) {}
139 virtual ~BugReport();
141 const BugType& getBugType() const { return BT; }
142 BugType& getBugType() { return BT; }
144 const ExplodedNode *getErrorNode() const { return ErrorNode; }
146 const StringRef getDescription() const { return Description; }
148 const StringRef getShortDescription() const {
149 return ShortDescription.empty() ? Description : ShortDescription;
152 /// Indicates whether or not any path pruning should take place
153 /// when generating a PathDiagnostic from this BugReport.
154 bool shouldPrunePath() const { return !DoNotPrunePath; }
156 /// Disable all path pruning when generating a PathDiagnostic.
157 void disablePathPruning() { DoNotPrunePath = true; }
159 void markInteresting(SymbolRef sym);
160 void markInteresting(const MemRegion *R);
161 void markInteresting(SVal V);
163 bool isInteresting(SymbolRef sym) const;
164 bool isInteresting(const MemRegion *R) const;
165 bool isInteresting(SVal V) const;
167 unsigned getConfigurationChangeToken() const {
168 return ConfigurationChangeToken;
171 /// Return the canonical declaration, be it a method or class, where
172 /// this issue semantically occurred.
173 const Decl *getDeclWithIssue() const;
175 /// Specifically set the Decl where an issue occurred. This isn't necessary
176 /// for BugReports that cover a path as it will be automatically inferred.
177 void setDeclWithIssue(const Decl *declWithIssue) {
178 DeclWithIssue = declWithIssue;
181 /// \brief This allows for addition of meta data to the diagnostic.
183 /// Currently, only the HTMLDiagnosticClient knows how to display it.
184 void addExtraText(StringRef S) {
185 ExtraText.push_back(S);
188 virtual const ExtraTextList &getExtraText() {
192 /// \brief Return the "definitive" location of the reported bug.
194 /// While a bug can span an entire path, usually there is a specific
195 /// location that can be used to identify where the key issue occurred.
196 /// This location is used by clients rendering diagnostics.
197 virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
199 const Stmt *getStmt() const;
201 /// \brief Add a range to a bug report.
203 /// Ranges are used to highlight regions of interest in the source code.
204 /// They should be at the same source code line as the BugReport location.
205 /// By default, the source range of the statement corresponding to the error
206 /// node will be used; add a single invalid range to specify absence of
208 void addRange(SourceRange R) {
209 assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
210 "to specify that the report does not have a range.");
214 /// \brief Get the SourceRanges associated with the report.
215 virtual std::pair<ranges_iterator, ranges_iterator> getRanges();
217 /// \brief Add custom or predefined bug report visitors to this report.
219 /// The visitors should be used when the default trace is not sufficient.
220 /// For example, they allow constructing a more elaborate trace.
221 /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(),
222 /// registerFindLastStore(), registerNilReceiverVisitor(), and
223 /// registerVarDeclsLastStore().
224 void addVisitor(BugReporterVisitor *visitor);
226 /// Iterators through the custom diagnostic visitors.
227 visitor_iterator visitor_begin() { return Callbacks.begin(); }
228 visitor_iterator visitor_end() { return Callbacks.end(); }
230 /// Profile to identify equivalent bug reports for error report coalescing.
231 /// Reports are uniqued to ensure that we do not emit multiple diagnostics
233 virtual void Profile(llvm::FoldingSetNodeID& hash) const;
236 } // end ento namespace
237 } // end clang namespace
240 template<> struct ilist_traits<clang::ento::BugReport>
241 : public ilist_default_traits<clang::ento::BugReport> {
242 clang::ento::BugReport *createSentinel() const {
243 return static_cast<clang::ento::BugReport *>(&Sentinel);
245 void destroySentinel(clang::ento::BugReport *) const {}
247 clang::ento::BugReport *provideInitialHead() const {
248 return createSentinel();
250 clang::ento::BugReport *ensureHead(clang::ento::BugReport *) const {
251 return createSentinel();
254 mutable ilist_half_node<clang::ento::BugReport> Sentinel;
261 //===----------------------------------------------------------------------===//
262 // BugTypes (collections of related reports).
263 //===----------------------------------------------------------------------===//
265 class BugReportEquivClass : public llvm::FoldingSetNode {
266 /// List of *owned* BugReport objects.
267 llvm::ilist<BugReport> Reports;
269 friend class BugReporter;
270 void AddReport(BugReport* R) { Reports.push_back(R); }
272 BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
273 ~BugReportEquivClass();
275 void Profile(llvm::FoldingSetNodeID& ID) const {
276 assert(!Reports.empty());
277 Reports.front().Profile(ID);
280 typedef llvm::ilist<BugReport>::iterator iterator;
281 typedef llvm::ilist<BugReport>::const_iterator const_iterator;
283 iterator begin() { return Reports.begin(); }
284 iterator end() { return Reports.end(); }
286 const_iterator begin() const { return Reports.begin(); }
287 const_iterator end() const { return Reports.end(); }
290 //===----------------------------------------------------------------------===//
291 // BugReporter and friends.
292 //===----------------------------------------------------------------------===//
294 class BugReporterData {
296 virtual ~BugReporterData();
297 virtual DiagnosticsEngine& getDiagnostic() = 0;
298 virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0;
299 virtual ASTContext &getASTContext() = 0;
300 virtual SourceManager& getSourceManager() = 0;
303 /// BugReporter is a utility class for generating PathDiagnostics for analysis.
304 /// It collects the BugReports and BugTypes and knows how to generate
305 /// and flush the corresponding diagnostics.
308 enum Kind { BaseBRKind, GRBugReporterKind };
311 typedef llvm::ImmutableSet<BugType*> BugTypesTy;
312 BugTypesTy::Factory F;
318 /// Generate and flush the diagnostics for the given bug report.
319 void FlushReport(BugReportEquivClass& EQ);
321 /// The set of bug reports tracked by the BugReporter.
322 llvm::FoldingSet<BugReportEquivClass> EQClasses;
323 /// A vector of BugReports for tracking the allocated pointers and cleanup.
324 std::vector<BugReportEquivClass *> EQClassesVector;
327 BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
331 BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
333 virtual ~BugReporter();
335 /// \brief Generate and flush diagnostics for all bug reports.
338 Kind getKind() const { return kind; }
340 DiagnosticsEngine& getDiagnostic() {
341 return D.getDiagnostic();
344 PathDiagnosticConsumer* getPathDiagnosticConsumer() {
345 return D.getPathDiagnosticConsumer();
348 /// \brief Iterator over the set of BugTypes tracked by the BugReporter.
349 typedef BugTypesTy::iterator iterator;
350 iterator begin() { return BugTypes.begin(); }
351 iterator end() { return BugTypes.end(); }
353 /// \brief Iterator over the set of BugReports tracked by the BugReporter.
354 typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
355 EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
356 EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
358 ASTContext &getContext() { return D.getASTContext(); }
360 SourceManager& getSourceManager() { return D.getSourceManager(); }
362 virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
363 SmallVectorImpl<BugReport *> &bugReports) {}
365 void Register(BugType *BT);
367 /// \brief Add the given report to the set of reports tracked by BugReporter.
369 /// The reports are usually generated by the checkers. Further, they are
370 /// folded based on the profile value, which is done to coalesce similar
372 void EmitReport(BugReport *R);
374 void EmitBasicReport(const Decl *DeclWithIssue,
375 StringRef BugName, StringRef BugCategory,
376 StringRef BugStr, PathDiagnosticLocation Loc,
377 SourceRange* RangeBeg, unsigned NumRanges);
379 void EmitBasicReport(const Decl *DeclWithIssue,
380 StringRef BugName, StringRef BugCategory,
381 StringRef BugStr, PathDiagnosticLocation Loc) {
382 EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0);
385 void EmitBasicReport(const Decl *DeclWithIssue,
386 StringRef BugName, StringRef Category,
387 StringRef BugStr, PathDiagnosticLocation Loc,
389 EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1);
392 static bool classof(const BugReporter* R) { return true; }
395 llvm::StringMap<BugType *> StrBugTypes;
397 /// \brief Returns a BugType that is associated with the given name and
399 BugType *getBugTypeForName(StringRef name, StringRef category);
402 // FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
403 class GRBugReporter : public BugReporter {
406 GRBugReporter(BugReporterData& d, ExprEngine& eng)
407 : BugReporter(d, GRBugReporterKind), Eng(eng) {}
409 virtual ~GRBugReporter();
411 /// getEngine - Return the analysis engine used to analyze a given
412 /// function or method.
413 ExprEngine &getEngine() { return Eng; }
415 /// getGraph - Get the exploded graph created by the analysis engine
416 /// for the analyzed method or function.
417 ExplodedGraph &getGraph();
419 /// getStateManager - Return the state manager used by the analysis
421 ProgramStateManager &getStateManager();
423 virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
424 SmallVectorImpl<BugReport*> &bugReports);
426 /// classof - Used by isa<>, cast<>, and dyn_cast<>.
427 static bool classof(const BugReporter* R) {
428 return R->getKind() == GRBugReporterKind;
432 class BugReporterContext {
433 virtual void anchor();
436 BugReporterContext(GRBugReporter& br) : BR(br) {}
438 virtual ~BugReporterContext() {}
440 GRBugReporter& getBugReporter() { return BR; }
442 ExplodedGraph &getGraph() { return BR.getGraph(); }
444 ProgramStateManager& getStateManager() {
445 return BR.getStateManager();
448 SValBuilder& getSValBuilder() {
449 return getStateManager().getSValBuilder();
452 ASTContext &getASTContext() {
453 return BR.getContext();
456 SourceManager& getSourceManager() {
457 return BR.getSourceManager();
460 virtual BugReport::NodeResolver& getNodeResolver() = 0;
463 } // end GR namespace
465 } // end clang namespace