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