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