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