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