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