PathDiagnostic.h revision bac341346f3c8e713a8f165120fd54b500ee3189
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 {
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 };
265  enum DisplayHint { Above, Below };
266
267private:
268  const std::string str;
269  std::vector<FixItHint> FixItHints;
270  const Kind kind;
271  const DisplayHint Hint;
272  std::vector<SourceRange> ranges;
273
274  // Do not implement:
275  PathDiagnosticPiece();
276  PathDiagnosticPiece(const PathDiagnosticPiece &P);
277  PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
278
279protected:
280  PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
281
282  PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
283
284public:
285  virtual ~PathDiagnosticPiece();
286
287  const std::string& getString() const { return str; }
288
289  /// getDisplayHint - Return a hint indicating where the diagnostic should
290  ///  be displayed by the PathDiagnosticConsumer.
291  DisplayHint getDisplayHint() const { return Hint; }
292
293  virtual PathDiagnosticLocation getLocation() const = 0;
294  virtual void flattenLocations() = 0;
295
296  Kind getKind() const { return kind; }
297
298  void addRange(SourceRange R) {
299    if (!R.isValid())
300      return;
301    ranges.push_back(R);
302  }
303
304  void addRange(SourceLocation B, SourceLocation E) {
305    if (!B.isValid() || !E.isValid())
306      return;
307    ranges.push_back(SourceRange(B,E));
308  }
309
310  void addFixItHint(const FixItHint& Hint) {
311    FixItHints.push_back(Hint);
312  }
313
314  typedef const SourceRange* range_iterator;
315
316  range_iterator ranges_begin() const {
317    return ranges.empty() ? NULL : &ranges[0];
318  }
319
320  range_iterator ranges_end() const {
321    return ranges_begin() + ranges.size();
322  }
323
324  typedef const FixItHint *fixit_iterator;
325
326  fixit_iterator fixit_begin() const {
327    return FixItHints.empty()? 0 : &FixItHints[0];
328  }
329
330  fixit_iterator fixit_end() const {
331    return FixItHints.empty()? 0
332                   : &FixItHints[0] + FixItHints.size();
333  }
334
335  static inline bool classof(const PathDiagnosticPiece *P) {
336    return true;
337  }
338
339  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
340};
341
342class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
343private:
344  PathDiagnosticLocation Pos;
345public:
346  PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
347                          StringRef s,
348                          PathDiagnosticPiece::Kind k,
349                          bool addPosRange = true)
350  : PathDiagnosticPiece(s, k), Pos(pos) {
351    assert(Pos.isValid() && Pos.asLocation().isValid() &&
352           "PathDiagnosticSpotPiece's must have a valid location.");
353    if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
354  }
355
356  PathDiagnosticLocation getLocation() const { return Pos; }
357  virtual void flattenLocations() { Pos.flatten(); }
358
359  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
360};
361
362class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
363
364public:
365  PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
366                           StringRef s, bool addPosRange = true)
367    : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
368
369  ~PathDiagnosticEventPiece();
370
371  static inline bool classof(const PathDiagnosticPiece *P) {
372    return P->getKind() == Event;
373  }
374};
375
376class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
377  std::vector<PathDiagnosticLocationPair> LPairs;
378public:
379  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
380                                 const PathDiagnosticLocation &endPos,
381                                 StringRef s)
382    : PathDiagnosticPiece(s, ControlFlow) {
383      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
384    }
385
386  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
387                                 const PathDiagnosticLocation &endPos)
388    : PathDiagnosticPiece(ControlFlow) {
389      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
390    }
391
392  ~PathDiagnosticControlFlowPiece();
393
394  PathDiagnosticLocation getStartLocation() const {
395    assert(!LPairs.empty() &&
396           "PathDiagnosticControlFlowPiece needs at least one location.");
397    return LPairs[0].getStart();
398  }
399
400  PathDiagnosticLocation getEndLocation() const {
401    assert(!LPairs.empty() &&
402           "PathDiagnosticControlFlowPiece needs at least one location.");
403    return LPairs[0].getEnd();
404  }
405
406  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
407
408  virtual PathDiagnosticLocation getLocation() const {
409    return getStartLocation();
410  }
411
412  typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
413  iterator begin() { return LPairs.begin(); }
414  iterator end()   { return LPairs.end(); }
415
416  virtual void flattenLocations() {
417    for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
418  }
419
420  typedef std::vector<PathDiagnosticLocationPair>::const_iterator
421          const_iterator;
422  const_iterator begin() const { return LPairs.begin(); }
423  const_iterator end() const   { return LPairs.end(); }
424
425  static inline bool classof(const PathDiagnosticPiece *P) {
426    return P->getKind() == ControlFlow;
427  }
428
429  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
430};
431
432class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
433  std::vector<PathDiagnosticPiece*> SubPieces;
434public:
435  PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
436    : PathDiagnosticSpotPiece(pos, "", Macro) {}
437
438  ~PathDiagnosticMacroPiece();
439
440  bool containsEvent() const;
441
442  void push_back(PathDiagnosticPiece *P) { SubPieces.push_back(P); }
443
444  typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
445  iterator begin() { return SubPieces.begin(); }
446  iterator end() { return SubPieces.end(); }
447
448  virtual void flattenLocations() {
449    PathDiagnosticSpotPiece::flattenLocations();
450    for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations();
451  }
452
453  typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator;
454  const_iterator begin() const { return SubPieces.begin(); }
455  const_iterator end() const { return SubPieces.end(); }
456
457  static inline bool classof(const PathDiagnosticPiece *P) {
458    return P->getKind() == Macro;
459  }
460
461  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
462};
463
464/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
465///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
466///  each which represent the pieces of the path.
467class PathDiagnostic : public llvm::FoldingSetNode {
468  std::deque<PathDiagnosticPiece*> path;
469  unsigned Size;
470  std::string BugType;
471  std::string Desc;
472  std::string Category;
473  std::deque<std::string> OtherDesc;
474
475public:
476  PathDiagnostic();
477
478  PathDiagnostic(StringRef bugtype, StringRef desc,
479                 StringRef category);
480
481  ~PathDiagnostic();
482
483  StringRef getDescription() const { return Desc; }
484  StringRef getBugType() const { return BugType; }
485  StringRef getCategory() const { return Category; }
486
487  typedef std::deque<std::string>::const_iterator meta_iterator;
488  meta_iterator meta_begin() const { return OtherDesc.begin(); }
489  meta_iterator meta_end() const { return OtherDesc.end(); }
490  void addMeta(StringRef s) { OtherDesc.push_back(s); }
491
492  PathDiagnosticLocation getLocation() const {
493    assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
494    return rbegin()->getLocation();
495  }
496
497  void push_front(PathDiagnosticPiece *piece) {
498    assert(piece);
499    path.push_front(piece);
500    ++Size;
501  }
502
503  void push_back(PathDiagnosticPiece *piece) {
504    assert(piece);
505    path.push_back(piece);
506    ++Size;
507  }
508
509  PathDiagnosticPiece *back() {
510    return path.back();
511  }
512
513  const PathDiagnosticPiece *back() const {
514    return path.back();
515  }
516
517  unsigned size() const { return Size; }
518  bool empty() const { return Size == 0; }
519
520  void resetPath(bool deletePieces = true);
521
522  class iterator {
523  public:
524    typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy;
525
526    typedef PathDiagnosticPiece              value_type;
527    typedef value_type&                      reference;
528    typedef value_type*                      pointer;
529    typedef ptrdiff_t                        difference_type;
530    typedef std::bidirectional_iterator_tag  iterator_category;
531
532  private:
533    ImplTy I;
534
535  public:
536    iterator(const ImplTy& i) : I(i) {}
537
538    bool operator==(const iterator &X) const { return I == X.I; }
539    bool operator!=(const iterator &X) const { return I != X.I; }
540
541    PathDiagnosticPiece& operator*() const { return **I; }
542    PathDiagnosticPiece *operator->() const { return *I; }
543
544    iterator &operator++() { ++I; return *this; }
545    iterator &operator--() { --I; return *this; }
546  };
547
548  class const_iterator {
549  public:
550    typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy;
551
552    typedef const PathDiagnosticPiece        value_type;
553    typedef value_type&                      reference;
554    typedef value_type*                      pointer;
555    typedef ptrdiff_t                        difference_type;
556    typedef std::bidirectional_iterator_tag  iterator_category;
557
558  private:
559    ImplTy I;
560
561  public:
562    const_iterator(const ImplTy& i) : I(i) {}
563
564    bool operator==(const const_iterator &X) const { return I == X.I; }
565    bool operator!=(const const_iterator &X) const { return I != X.I; }
566
567    reference operator*() const { return **I; }
568    pointer operator->() const { return *I; }
569
570    const_iterator &operator++() { ++I; return *this; }
571    const_iterator &operator--() { --I; return *this; }
572  };
573
574  typedef std::reverse_iterator<iterator>       reverse_iterator;
575  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
576
577  // forward iterator creation methods.
578
579  iterator begin() { return path.begin(); }
580  iterator end() { return path.end(); }
581
582  const_iterator begin() const { return path.begin(); }
583  const_iterator end() const { return path.end(); }
584
585  // reverse iterator creation methods.
586  reverse_iterator rbegin()            { return reverse_iterator(end()); }
587  const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
588  reverse_iterator rend()              { return reverse_iterator(begin()); }
589  const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
590
591  void flattenLocations() {
592    for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations();
593  }
594
595  void Profile(llvm::FoldingSetNodeID &ID) const;
596
597  void FullProfile(llvm::FoldingSetNodeID &ID) const;
598};
599
600} // end GR namespace
601
602} //end clang namespace
603
604#endif
605