PathDiagnostic.h revision 4fdf97bf51d2a156cec3232efd6dae110aa02aa0
1//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- 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 the PathDiagnostic-related interfaces.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
15#define LLVM_CLANG_PATH_DIAGNOSTIC_H
16
17#include "clang/Basic/Diagnostic.h"
18#include "llvm/ADT/FoldingSet.h"
19#include <deque>
20#include <iterator>
21#include <string>
22#include <vector>
23
24namespace clang {
25
26class Decl;
27class LocationContext;
28class ProgramPoint;
29class SourceManager;
30class Stmt;
31
32namespace ento {
33
34class ExplodedNode;
35
36//===----------------------------------------------------------------------===//
37// High-level interface for handlers of path-sensitive diagnostics.
38//===----------------------------------------------------------------------===//
39
40class PathDiagnostic;
41
42class PathDiagnosticClient : public DiagnosticClient  {
43public:
44  PathDiagnosticClient() {}
45
46  virtual ~PathDiagnosticClient() {}
47
48  virtual void
49  FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade = 0) = 0;
50
51  void FlushDiagnostics(SmallVectorImpl<std::string> &FilesMade) {
52    FlushDiagnostics(&FilesMade);
53  }
54
55  virtual StringRef getName() const = 0;
56
57  virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
58                                const DiagnosticInfo &Info);
59  void HandlePathDiagnostic(const PathDiagnostic* D);
60
61  enum PathGenerationScheme { Minimal, Extensive };
62  virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
63  virtual bool supportsLogicalOpControlFlow() const { return false; }
64  virtual bool supportsAllBlockEdges() const { return false; }
65  virtual bool useVerboseDescription() const { return true; }
66
67protected:
68  /// The actual logic for handling path diagnostics, as implemented
69  /// by subclasses of PathDiagnosticClient.
70  virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D) = 0;
71
72};
73
74//===----------------------------------------------------------------------===//
75// Path-sensitive diagnostics.
76//===----------------------------------------------------------------------===//
77
78class PathDiagnosticRange : public SourceRange {
79public:
80  const bool isPoint;
81
82  PathDiagnosticRange(const SourceRange &R, bool isP = false)
83    : SourceRange(R), isPoint(isP) {}
84};
85
86class PathDiagnosticLocation {
87private:
88  enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
89  SourceRange R;
90  const Stmt *S;
91  const Decl *D;
92  const SourceManager *SM;
93  const LocationContext *LC;
94public:
95  PathDiagnosticLocation()
96    : K(SingleLocK), S(0), D(0), SM(0), LC(0) {}
97
98  PathDiagnosticLocation(FullSourceLoc L)
99    : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()), LC(0) {}
100
101  /// Constructs a location when no specific statement is available.
102  /// Defaults to end of brace for the enclosing function body.
103  PathDiagnosticLocation(const LocationContext *lc, const SourceManager &sm);
104
105  PathDiagnosticLocation(const Stmt *s,
106                         const SourceManager &sm,
107                         const LocationContext *lc)
108    : K(StmtK), S(s), D(0), SM(&sm), LC(lc) {}
109
110  PathDiagnosticLocation(SourceRange r, const SourceManager &sm)
111    : K(RangeK), R(r), S(0), D(0), SM(&sm), LC(0) {}
112
113  PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
114    : K(DeclK), S(0), D(d), SM(&sm), LC(0) {}
115
116  /// Create a location corresponding to the given valid ExplodedNode.
117  PathDiagnosticLocation(const ProgramPoint& P, const SourceManager &SMng);
118
119  /// Create a location corresponding to the next valid ExplodedNode as end
120  /// of path location.
121  static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
122                                                const SourceManager &SM);
123
124  bool operator==(const PathDiagnosticLocation &X) const {
125    return K == X.K && R == X.R && S == X.S && D == X.D && LC == X.LC;
126  }
127
128  bool operator!=(const PathDiagnosticLocation &X) const {
129    return !(*this == X);
130  }
131
132  bool isValid() const {
133    return SM != 0;
134  }
135
136  FullSourceLoc asLocation() const;
137  PathDiagnosticRange asRange() const;
138  const Stmt *asStmt() const { assert(isValid()); return S; }
139  const Decl *asDecl() const { assert(isValid()); return D; }
140
141  bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
142
143  void invalidate() {
144    *this = PathDiagnosticLocation();
145  }
146
147  void flatten();
148
149  const SourceManager& getManager() const { assert(isValid()); return *SM; }
150  const LocationContext* getLocationContext() const { return LC; }
151
152  void Profile(llvm::FoldingSetNodeID &ID) const;
153};
154
155class PathDiagnosticLocationPair {
156private:
157  PathDiagnosticLocation Start, End;
158public:
159  PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
160                             const PathDiagnosticLocation &end)
161    : Start(start), End(end) {}
162
163  const PathDiagnosticLocation &getStart() const { return Start; }
164  const PathDiagnosticLocation &getEnd() const { return End; }
165
166  void flatten() {
167    Start.flatten();
168    End.flatten();
169  }
170
171  void Profile(llvm::FoldingSetNodeID &ID) const {
172    Start.Profile(ID);
173    End.Profile(ID);
174  }
175};
176
177//===----------------------------------------------------------------------===//
178// Path "pieces" for path-sensitive diagnostics.
179//===----------------------------------------------------------------------===//
180
181class PathDiagnosticPiece {
182public:
183  enum Kind { ControlFlow, Event, Macro };
184  enum DisplayHint { Above, Below };
185
186private:
187  const std::string str;
188  std::vector<FixItHint> FixItHints;
189  const Kind kind;
190  const DisplayHint Hint;
191  std::vector<SourceRange> ranges;
192
193  // Do not implement:
194  PathDiagnosticPiece();
195  PathDiagnosticPiece(const PathDiagnosticPiece &P);
196  PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
197
198protected:
199  PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
200
201  PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
202
203public:
204  virtual ~PathDiagnosticPiece();
205
206  const std::string& getString() const { return str; }
207
208  /// getDisplayHint - Return a hint indicating where the diagnostic should
209  ///  be displayed by the PathDiagnosticClient.
210  DisplayHint getDisplayHint() const { return Hint; }
211
212  virtual PathDiagnosticLocation getLocation() const = 0;
213  virtual void flattenLocations() = 0;
214
215  Kind getKind() const { return kind; }
216
217  void addRange(SourceRange R) { ranges.push_back(R); }
218
219  void addRange(SourceLocation B, SourceLocation E) {
220    ranges.push_back(SourceRange(B,E));
221  }
222
223  void addFixItHint(const FixItHint& Hint) {
224    FixItHints.push_back(Hint);
225  }
226
227  typedef const SourceRange* range_iterator;
228
229  range_iterator ranges_begin() const {
230    return ranges.empty() ? NULL : &ranges[0];
231  }
232
233  range_iterator ranges_end() const {
234    return ranges_begin() + ranges.size();
235  }
236
237  typedef const FixItHint *fixit_iterator;
238
239  fixit_iterator fixit_begin() const {
240    return FixItHints.empty()? 0 : &FixItHints[0];
241  }
242
243  fixit_iterator fixit_end() const {
244    return FixItHints.empty()? 0
245                   : &FixItHints[0] + FixItHints.size();
246  }
247
248  static inline bool classof(const PathDiagnosticPiece *P) {
249    return true;
250  }
251
252  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
253};
254
255class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
256private:
257  PathDiagnosticLocation Pos;
258public:
259  PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
260                          StringRef s,
261                          PathDiagnosticPiece::Kind k,
262                          bool addPosRange = true)
263  : PathDiagnosticPiece(s, k), Pos(pos) {
264    assert(Pos.asLocation().isValid() &&
265           "PathDiagnosticSpotPiece's must have a valid location.");
266    if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
267  }
268
269  PathDiagnosticLocation getLocation() const { return Pos; }
270  virtual void flattenLocations() { Pos.flatten(); }
271
272  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
273};
274
275class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
276
277public:
278  PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
279                           StringRef s, bool addPosRange = true)
280    : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
281
282  ~PathDiagnosticEventPiece();
283
284  static inline bool classof(const PathDiagnosticPiece *P) {
285    return P->getKind() == Event;
286  }
287};
288
289class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
290  std::vector<PathDiagnosticLocationPair> LPairs;
291public:
292  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
293                                 const PathDiagnosticLocation &endPos,
294                                 StringRef s)
295    : PathDiagnosticPiece(s, ControlFlow) {
296      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
297    }
298
299  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
300                                 const PathDiagnosticLocation &endPos)
301    : PathDiagnosticPiece(ControlFlow) {
302      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
303    }
304
305  ~PathDiagnosticControlFlowPiece();
306
307  PathDiagnosticLocation getStartLocation() const {
308    assert(!LPairs.empty() &&
309           "PathDiagnosticControlFlowPiece needs at least one location.");
310    return LPairs[0].getStart();
311  }
312
313  PathDiagnosticLocation getEndLocation() const {
314    assert(!LPairs.empty() &&
315           "PathDiagnosticControlFlowPiece needs at least one location.");
316    return LPairs[0].getEnd();
317  }
318
319  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
320
321  virtual PathDiagnosticLocation getLocation() const {
322    return getStartLocation();
323  }
324
325  typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
326  iterator begin() { return LPairs.begin(); }
327  iterator end()   { return LPairs.end(); }
328
329  virtual void flattenLocations() {
330    for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
331  }
332
333  typedef std::vector<PathDiagnosticLocationPair>::const_iterator
334          const_iterator;
335  const_iterator begin() const { return LPairs.begin(); }
336  const_iterator end() const   { return LPairs.end(); }
337
338  static inline bool classof(const PathDiagnosticPiece *P) {
339    return P->getKind() == ControlFlow;
340  }
341
342  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
343};
344
345class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
346  std::vector<PathDiagnosticPiece*> SubPieces;
347public:
348  PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
349    : PathDiagnosticSpotPiece(pos, "", Macro) {}
350
351  ~PathDiagnosticMacroPiece();
352
353  bool containsEvent() const;
354
355  void push_back(PathDiagnosticPiece *P) { SubPieces.push_back(P); }
356
357  typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
358  iterator begin() { return SubPieces.begin(); }
359  iterator end() { return SubPieces.end(); }
360
361  virtual void flattenLocations() {
362    PathDiagnosticSpotPiece::flattenLocations();
363    for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations();
364  }
365
366  typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator;
367  const_iterator begin() const { return SubPieces.begin(); }
368  const_iterator end() const { return SubPieces.end(); }
369
370  static inline bool classof(const PathDiagnosticPiece *P) {
371    return P->getKind() == Macro;
372  }
373
374  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
375};
376
377/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
378///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
379///  each which represent the pieces of the path.
380class PathDiagnostic : public llvm::FoldingSetNode {
381  std::deque<PathDiagnosticPiece*> path;
382  unsigned Size;
383  std::string BugType;
384  std::string Desc;
385  std::string Category;
386  std::deque<std::string> OtherDesc;
387
388public:
389  PathDiagnostic();
390
391  PathDiagnostic(StringRef bugtype, StringRef desc,
392                 StringRef category);
393
394  ~PathDiagnostic();
395
396  StringRef getDescription() const { return Desc; }
397  StringRef getBugType() const { return BugType; }
398  StringRef getCategory() const { return Category; }
399
400  typedef std::deque<std::string>::const_iterator meta_iterator;
401  meta_iterator meta_begin() const { return OtherDesc.begin(); }
402  meta_iterator meta_end() const { return OtherDesc.end(); }
403  void addMeta(StringRef s) { OtherDesc.push_back(s); }
404
405  PathDiagnosticLocation getLocation() const {
406    assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
407    return rbegin()->getLocation();
408  }
409
410  void push_front(PathDiagnosticPiece *piece) {
411    assert(piece);
412    path.push_front(piece);
413    ++Size;
414  }
415
416  void push_back(PathDiagnosticPiece *piece) {
417    assert(piece);
418    path.push_back(piece);
419    ++Size;
420  }
421
422  PathDiagnosticPiece *back() {
423    return path.back();
424  }
425
426  const PathDiagnosticPiece *back() const {
427    return path.back();
428  }
429
430  unsigned size() const { return Size; }
431  bool empty() const { return Size == 0; }
432
433  void resetPath(bool deletePieces = true);
434
435  class iterator {
436  public:
437    typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy;
438
439    typedef PathDiagnosticPiece              value_type;
440    typedef value_type&                      reference;
441    typedef value_type*                      pointer;
442    typedef ptrdiff_t                        difference_type;
443    typedef std::bidirectional_iterator_tag  iterator_category;
444
445  private:
446    ImplTy I;
447
448  public:
449    iterator(const ImplTy& i) : I(i) {}
450
451    bool operator==(const iterator &X) const { return I == X.I; }
452    bool operator!=(const iterator &X) const { return I != X.I; }
453
454    PathDiagnosticPiece& operator*() const { return **I; }
455    PathDiagnosticPiece *operator->() const { return *I; }
456
457    iterator &operator++() { ++I; return *this; }
458    iterator &operator--() { --I; return *this; }
459  };
460
461  class const_iterator {
462  public:
463    typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy;
464
465    typedef const PathDiagnosticPiece        value_type;
466    typedef value_type&                      reference;
467    typedef value_type*                      pointer;
468    typedef ptrdiff_t                        difference_type;
469    typedef std::bidirectional_iterator_tag  iterator_category;
470
471  private:
472    ImplTy I;
473
474  public:
475    const_iterator(const ImplTy& i) : I(i) {}
476
477    bool operator==(const const_iterator &X) const { return I == X.I; }
478    bool operator!=(const const_iterator &X) const { return I != X.I; }
479
480    reference operator*() const { return **I; }
481    pointer operator->() const { return *I; }
482
483    const_iterator &operator++() { ++I; return *this; }
484    const_iterator &operator--() { --I; return *this; }
485  };
486
487  typedef std::reverse_iterator<iterator>       reverse_iterator;
488  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
489
490  // forward iterator creation methods.
491
492  iterator begin() { return path.begin(); }
493  iterator end() { return path.end(); }
494
495  const_iterator begin() const { return path.begin(); }
496  const_iterator end() const { return path.end(); }
497
498  // reverse iterator creation methods.
499  reverse_iterator rbegin()            { return reverse_iterator(end()); }
500  const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
501  reverse_iterator rend()              { return reverse_iterator(begin()); }
502  const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
503
504  void flattenLocations() {
505    for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations();
506  }
507
508  void Profile(llvm::FoldingSetNodeID &ID) const;
509};
510
511} // end GR namespace
512
513} //end clang namespace
514
515#endif
516