BugReporter.h revision 07189521a15d9c088216b943649cb9fe231cbb57
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/ilist.h"
24#include "llvm/ADT/ilist_node.h"
25#include "llvm/ADT/ImmutableSet.h"
26#include "llvm/ADT/DenseSet.h"
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 : public llvm::ilist_node<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 SmallVector<BugReporterVisitor *, 8> VisitorList;
64  typedef VisitorList::iterator visitor_iterator;
65  typedef SmallVector<StringRef, 2> ExtraTextList;
66
67protected:
68  friend class BugReporter;
69  friend class BugReportEquivClass;
70
71  BugType& BT;
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;
80
81  typedef llvm::DenseSet<SymbolRef> Symbols;
82  typedef llvm::DenseSet<const MemRegion *> Regions;
83
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;
88
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;
93
94  /// A set of custom visitors which generate "event" diagnostics at
95  /// interesting points in the path.
96  VisitorList Callbacks;
97
98  /// Used for ensuring the visitors are only added once.
99  llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
100
101  /// Used for clients to tell if the report's configuration has changed
102  /// since the last time they checked.
103  unsigned ConfigurationChangeToken;
104
105public:
106  BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
107    : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode),
108      ConfigurationChangeToken(0) {}
109
110  BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
111            const ExplodedNode *errornode)
112    : BT(bt), DeclWithIssue(0), ShortDescription(shortDesc), Description(desc),
113      ErrorNode(errornode), ConfigurationChangeToken(0) {}
114
115  BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l)
116    : BT(bt), DeclWithIssue(0), Description(desc), Location(l), ErrorNode(0),
117      ConfigurationChangeToken(0) {}
118
119  /// \brief Create a BugReport with a custom uniqueing location.
120  ///
121  /// The reports that have the same report location, description, bug type, and
122  /// ranges are uniqued - only one of the equivalent reports will be presented
123  /// to the user. This method allows to rest the location which should be used
124  /// for uniquing reports. For example, memory leaks checker, could set this to
125  /// the allocation site, rather then the location where the bug is reported.
126  BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode,
127            PathDiagnosticLocation LocationToUnique)
128    : BT(bt), DeclWithIssue(0), Description(desc),
129      UniqueingLocation(LocationToUnique),
130      ErrorNode(errornode), ConfigurationChangeToken(0) {}
131
132  virtual ~BugReport();
133
134  const BugType& getBugType() const { return BT; }
135  BugType& getBugType() { return BT; }
136
137  const ExplodedNode *getErrorNode() const { return ErrorNode; }
138
139  const StringRef getDescription() const { return Description; }
140
141  const StringRef getShortDescription() const {
142    return ShortDescription.empty() ? Description : ShortDescription;
143  }
144
145  void markInteresting(SymbolRef sym);
146  void markInteresting(const MemRegion *R);
147  void markInteresting(SVal V);
148
149  bool isInteresting(SymbolRef sym) const;
150  bool isInteresting(const MemRegion *R) const;
151  bool isInteresting(SVal V) const;
152
153  unsigned getConfigurationChangeToken() const {
154    return ConfigurationChangeToken;
155  }
156
157  /// Return the canonical declaration, be it a method or class, where
158  /// this issue semantically occurred.
159  const Decl *getDeclWithIssue() const;
160
161  /// Specifically set the Decl where an issue occurred.  This isn't necessary
162  /// for BugReports that cover a path as it will be automatically inferred.
163  void setDeclWithIssue(const Decl *declWithIssue) {
164    DeclWithIssue = declWithIssue;
165  }
166
167  /// \brief This allows for addition of meta data to the diagnostic.
168  ///
169  /// Currently, only the HTMLDiagnosticClient knows how to display it.
170  void addExtraText(StringRef S) {
171    ExtraText.push_back(S);
172  }
173
174  virtual const ExtraTextList &getExtraText() {
175    return ExtraText;
176  }
177
178  /// \brief Return the "definitive" location of the reported bug.
179  ///
180  ///  While a bug can span an entire path, usually there is a specific
181  ///  location that can be used to identify where the key issue occurred.
182  ///  This location is used by clients rendering diagnostics.
183  virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
184
185  const Stmt *getStmt() const;
186
187  /// \brief Add a range to a bug report.
188  ///
189  /// Ranges are used to highlight regions of interest in the source code.
190  /// They should be at the same source code line as the BugReport location.
191  /// By default, the source range of the statement corresponding to the error
192  /// node will be used; add a single invalid range to specify absence of
193  /// ranges.
194  void addRange(SourceRange R) {
195    assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
196                           "to specify that the report does not have a range.");
197    Ranges.push_back(R);
198  }
199
200  /// \brief Get the SourceRanges associated with the report.
201  virtual std::pair<ranges_iterator, ranges_iterator> getRanges();
202
203  /// \brief Add custom or predefined bug report visitors to this report.
204  ///
205  /// The visitors should be used when the default trace is not sufficient.
206  /// For example, they allow constructing a more elaborate trace.
207  /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(),
208  /// registerFindLastStore(), registerNilReceiverVisitor(), and
209  /// registerVarDeclsLastStore().
210  void addVisitor(BugReporterVisitor *visitor);
211
212	/// Iterators through the custom diagnostic visitors.
213  visitor_iterator visitor_begin() { return Callbacks.begin(); }
214  visitor_iterator visitor_end() { return Callbacks.end(); }
215
216  /// Profile to identify equivalent bug reports for error report coalescing.
217  /// Reports are uniqued to ensure that we do not emit multiple diagnostics
218  /// for each bug.
219  virtual void Profile(llvm::FoldingSetNodeID& hash) const;
220};
221
222} // end ento namespace
223} // end clang namespace
224
225namespace llvm {
226  template<> struct ilist_traits<clang::ento::BugReport>
227    : public ilist_default_traits<clang::ento::BugReport> {
228    clang::ento::BugReport *createSentinel() const {
229      return static_cast<clang::ento::BugReport *>(&Sentinel);
230    }
231    void destroySentinel(clang::ento::BugReport *) const {}
232
233    clang::ento::BugReport *provideInitialHead() const {
234      return createSentinel();
235    }
236    clang::ento::BugReport *ensureHead(clang::ento::BugReport *) const {
237      return createSentinel();
238    }
239  private:
240    mutable ilist_half_node<clang::ento::BugReport> Sentinel;
241  };
242}
243
244namespace clang {
245namespace ento {
246
247//===----------------------------------------------------------------------===//
248// BugTypes (collections of related reports).
249//===----------------------------------------------------------------------===//
250
251class BugReportEquivClass : public llvm::FoldingSetNode {
252  /// List of *owned* BugReport objects.
253  llvm::ilist<BugReport> Reports;
254
255  friend class BugReporter;
256  void AddReport(BugReport* R) { Reports.push_back(R); }
257public:
258  BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
259  ~BugReportEquivClass();
260
261  void Profile(llvm::FoldingSetNodeID& ID) const {
262    assert(!Reports.empty());
263    Reports.front().Profile(ID);
264  }
265
266  typedef llvm::ilist<BugReport>::iterator iterator;
267  typedef llvm::ilist<BugReport>::const_iterator const_iterator;
268
269  iterator begin() { return Reports.begin(); }
270  iterator end() { return Reports.end(); }
271
272  const_iterator begin() const { return Reports.begin(); }
273  const_iterator end() const { return Reports.end(); }
274};
275
276//===----------------------------------------------------------------------===//
277// BugReporter and friends.
278//===----------------------------------------------------------------------===//
279
280class BugReporterData {
281public:
282  virtual ~BugReporterData();
283  virtual DiagnosticsEngine& getDiagnostic() = 0;
284  virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0;
285  virtual ASTContext &getASTContext() = 0;
286  virtual SourceManager& getSourceManager() = 0;
287};
288
289/// BugReporter is a utility class for generating PathDiagnostics for analysis.
290/// It collects the BugReports and BugTypes and knows how to generate
291/// and flush the corresponding diagnostics.
292class BugReporter {
293public:
294  enum Kind { BaseBRKind, GRBugReporterKind };
295
296private:
297  typedef llvm::ImmutableSet<BugType*> BugTypesTy;
298  BugTypesTy::Factory F;
299  BugTypesTy BugTypes;
300
301  const Kind kind;
302  BugReporterData& D;
303
304  /// Generate and flush the diagnostics for the given bug report.
305  void FlushReport(BugReportEquivClass& EQ);
306
307  /// The set of bug reports tracked by the BugReporter.
308  llvm::FoldingSet<BugReportEquivClass> EQClasses;
309  /// A vector of BugReports for tracking the allocated pointers and cleanup.
310  std::vector<BugReportEquivClass *> EQClassesVector;
311
312protected:
313  BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
314                                            D(d) {}
315
316public:
317  BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
318                                    D(d) {}
319  virtual ~BugReporter();
320
321  /// \brief Generate and flush diagnostics for all bug reports.
322  void FlushReports();
323
324  Kind getKind() const { return kind; }
325
326  DiagnosticsEngine& getDiagnostic() {
327    return D.getDiagnostic();
328  }
329
330  PathDiagnosticConsumer* getPathDiagnosticConsumer() {
331    return D.getPathDiagnosticConsumer();
332  }
333
334  /// \brief Iterator over the set of BugTypes tracked by the BugReporter.
335  typedef BugTypesTy::iterator iterator;
336  iterator begin() { return BugTypes.begin(); }
337  iterator end() { return BugTypes.end(); }
338
339  /// \brief Iterator over the set of BugReports tracked by the BugReporter.
340  typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
341  EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
342  EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
343
344  ASTContext &getContext() { return D.getASTContext(); }
345
346  SourceManager& getSourceManager() { return D.getSourceManager(); }
347
348  virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
349        SmallVectorImpl<BugReport *> &bugReports) {}
350
351  void Register(BugType *BT);
352
353  /// \brief Add the given report to the set of reports tracked by BugReporter.
354  ///
355  /// The reports are usually generated by the checkers. Further, they are
356  /// folded based on the profile value, which is done to coalesce similar
357  /// reports.
358  void EmitReport(BugReport *R);
359
360  void EmitBasicReport(const Decl *DeclWithIssue,
361                       StringRef BugName, StringRef BugStr,
362                       PathDiagnosticLocation Loc,
363                       SourceRange* RangeBeg, unsigned NumRanges);
364
365  void EmitBasicReport(const Decl *DeclWithIssue,
366                       StringRef BugName, StringRef BugCategory,
367                       StringRef BugStr, PathDiagnosticLocation Loc,
368                       SourceRange* RangeBeg, unsigned NumRanges);
369
370
371  void EmitBasicReport(const Decl *DeclWithIssue,
372                       StringRef BugName, StringRef BugStr,
373                       PathDiagnosticLocation Loc) {
374    EmitBasicReport(DeclWithIssue, BugName, BugStr, Loc, 0, 0);
375  }
376
377  void EmitBasicReport(const Decl *DeclWithIssue,
378                       StringRef BugName, StringRef BugCategory,
379                       StringRef BugStr, PathDiagnosticLocation Loc) {
380    EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0);
381  }
382
383  void EmitBasicReport(const Decl *DeclWithIssue,
384                       StringRef BugName, StringRef BugStr,
385                       PathDiagnosticLocation Loc,
386                       SourceRange R) {
387    EmitBasicReport(DeclWithIssue, BugName, BugStr, Loc, &R, 1);
388  }
389
390  void EmitBasicReport(const Decl *DeclWithIssue,
391                       StringRef BugName, StringRef Category,
392                       StringRef BugStr, PathDiagnosticLocation Loc,
393                       SourceRange R) {
394    EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1);
395  }
396
397  static bool classof(const BugReporter* R) { return true; }
398
399private:
400  llvm::StringMap<BugType *> StrBugTypes;
401
402  /// \brief Returns a BugType that is associated with the given name and
403  /// category.
404  BugType *getBugTypeForName(StringRef name, StringRef category);
405};
406
407// FIXME: Get rid of GRBugReporter.  It's the wrong abstraction.
408class GRBugReporter : public BugReporter {
409  ExprEngine& Eng;
410public:
411  GRBugReporter(BugReporterData& d, ExprEngine& eng)
412    : BugReporter(d, GRBugReporterKind), Eng(eng) {}
413
414  virtual ~GRBugReporter();
415
416  /// getEngine - Return the analysis engine used to analyze a given
417  ///  function or method.
418  ExprEngine &getEngine() { return Eng; }
419
420  /// getGraph - Get the exploded graph created by the analysis engine
421  ///  for the analyzed method or function.
422  ExplodedGraph &getGraph();
423
424  /// getStateManager - Return the state manager used by the analysis
425  ///  engine.
426  ProgramStateManager &getStateManager();
427
428  virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
429                     SmallVectorImpl<BugReport*> &bugReports);
430
431  /// classof - Used by isa<>, cast<>, and dyn_cast<>.
432  static bool classof(const BugReporter* R) {
433    return R->getKind() == GRBugReporterKind;
434  }
435};
436
437class BugReporterContext {
438  virtual void anchor();
439  GRBugReporter &BR;
440public:
441  BugReporterContext(GRBugReporter& br) : BR(br) {}
442
443  virtual ~BugReporterContext() {}
444
445  GRBugReporter& getBugReporter() { return BR; }
446
447  ExplodedGraph &getGraph() { return BR.getGraph(); }
448
449  ProgramStateManager& getStateManager() {
450    return BR.getStateManager();
451  }
452
453  SValBuilder& getSValBuilder() {
454    return getStateManager().getSValBuilder();
455  }
456
457  ASTContext &getASTContext() {
458    return BR.getContext();
459  }
460
461  SourceManager& getSourceManager() {
462    return BR.getSourceManager();
463  }
464
465  virtual BugReport::NodeResolver& getNodeResolver() = 0;
466};
467
468} // end GR namespace
469
470} // end clang namespace
471
472#endif
473