• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
PathDiagnosticClient()40   PathDiagnosticClient() {}
41 
~PathDiagnosticClient()42   virtual ~PathDiagnosticClient() {}
43 
44   virtual void
45   FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade = 0) = 0;
46 
FlushDiagnostics(llvm::SmallVectorImpl<std::string> & FilesMade)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 };
getGenerationScheme()58   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
supportsLogicalOpControlFlow()59   virtual bool supportsLogicalOpControlFlow() const { return false; }
supportsAllBlockEdges()60   virtual bool supportsAllBlockEdges() const { return false; }
useVerboseDescription()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)
SourceRange(R)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:
PathDiagnosticLocation()84   PathDiagnosticLocation()
85     : K(SingleLocK), S(0), D(0), SM(0) {}
86 
PathDiagnosticLocation(FullSourceLoc L)87   PathDiagnosticLocation(FullSourceLoc L)
88     : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {}
89 
PathDiagnosticLocation(const Stmt * s,const SourceManager & sm)90   PathDiagnosticLocation(const Stmt *s, const SourceManager &sm)
91     : K(StmtK), S(s), D(0), SM(&sm) {}
92 
PathDiagnosticLocation(SourceRange r,const SourceManager & sm)93   PathDiagnosticLocation(SourceRange r, const SourceManager &sm)
94     : K(RangeK), R(r), S(0), D(0), SM(&sm) {}
95 
PathDiagnosticLocation(const Decl * d,const SourceManager & sm)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 
isValid()116   bool isValid() const {
117     return SM != 0;
118   }
119 
getSourceManager()120   const SourceManager& getSourceManager() const { assert(isValid());return *SM;}
121 
122   FullSourceLoc asLocation() const;
123   PathDiagnosticRange asRange() const;
asStmt()124   const Stmt *asStmt() const { assert(isValid()); return S; }
asDecl()125   const Decl *asDecl() const { assert(isValid()); return D; }
126 
hasRange()127   bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
128 
invalidate()129   void invalidate() {
130     *this = PathDiagnosticLocation();
131   }
132 
133   void flatten();
134 
getManager()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:
PathDiagnosticLocationPair(const PathDiagnosticLocation & start,const PathDiagnosticLocation & end)144   PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
145                              const PathDiagnosticLocation &end)
146     : Start(start), End(end) {}
147 
getStart()148   const PathDiagnosticLocation &getStart() const { return Start; }
getEnd()149   const PathDiagnosticLocation &getEnd() const { return End; }
150 
flatten()151   void flatten() {
152     Start.flatten();
153     End.flatten();
154   }
155 
Profile(llvm::FoldingSetNodeID & ID)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 
getString()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.
getDisplayHint()195   DisplayHint getDisplayHint() const { return Hint; }
196 
197   virtual PathDiagnosticLocation getLocation() const = 0;
198   virtual void flattenLocations() = 0;
199 
getKind()200   Kind getKind() const { return kind; }
201 
addRange(SourceRange R)202   void addRange(SourceRange R) { ranges.push_back(R); }
203 
addRange(SourceLocation B,SourceLocation E)204   void addRange(SourceLocation B, SourceLocation E) {
205     ranges.push_back(SourceRange(B,E));
206   }
207 
addFixItHint(const FixItHint & Hint)208   void addFixItHint(const FixItHint& Hint) {
209     FixItHints.push_back(Hint);
210   }
211 
212   typedef const SourceRange* range_iterator;
213 
ranges_begin()214   range_iterator ranges_begin() const {
215     return ranges.empty() ? NULL : &ranges[0];
216   }
217 
ranges_end()218   range_iterator ranges_end() const {
219     return ranges_begin() + ranges.size();
220   }
221 
222   typedef const FixItHint *fixit_iterator;
223 
fixit_begin()224   fixit_iterator fixit_begin() const {
225     return FixItHints.empty()? 0 : &FixItHints[0];
226   }
227 
fixit_end()228   fixit_iterator fixit_end() const {
229     return FixItHints.empty()? 0
230                    : &FixItHints[0] + FixItHints.size();
231   }
232 
classof(const PathDiagnosticPiece * P)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)
PathDiagnosticPiece(s,k)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 
getLocation()254   PathDiagnosticLocation getLocation() const { return Pos; }
flattenLocations()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)
PathDiagnosticSpotPiece(pos,s,Event,addPosRange)265     : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
266 
267   ~PathDiagnosticEventPiece();
268 
classof(const PathDiagnosticPiece * P)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:
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation & startPos,const PathDiagnosticLocation & endPos,llvm::StringRef s)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 
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation & startPos,const PathDiagnosticLocation & endPos)284   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
285                                  const PathDiagnosticLocation &endPos)
286     : PathDiagnosticPiece(ControlFlow) {
287       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
288     }
289 
290   ~PathDiagnosticControlFlowPiece();
291 
getStartLocation()292   PathDiagnosticLocation getStartLocation() const {
293     assert(!LPairs.empty() &&
294            "PathDiagnosticControlFlowPiece needs at least one location.");
295     return LPairs[0].getStart();
296   }
297 
getEndLocation()298   PathDiagnosticLocation getEndLocation() const {
299     assert(!LPairs.empty() &&
300            "PathDiagnosticControlFlowPiece needs at least one location.");
301     return LPairs[0].getEnd();
302   }
303 
push_back(const PathDiagnosticLocationPair & X)304   void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
305 
getLocation()306   virtual PathDiagnosticLocation getLocation() const {
307     return getStartLocation();
308   }
309 
310   typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
begin()311   iterator begin() { return LPairs.begin(); }
end()312   iterator end()   { return LPairs.end(); }
313 
flattenLocations()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;
begin()320   const_iterator begin() const { return LPairs.begin(); }
end()321   const_iterator end() const   { return LPairs.end(); }
322 
classof(const PathDiagnosticPiece * P)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:
PathDiagnosticMacroPiece(const PathDiagnosticLocation & pos)333   PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
334     : PathDiagnosticSpotPiece(pos, "", Macro) {}
335 
336   ~PathDiagnosticMacroPiece();
337 
338   bool containsEvent() const;
339 
push_back(PathDiagnosticPiece * P)340   void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); }
341 
342   typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
begin()343   iterator begin() { return SubPieces.begin(); }
end()344   iterator end() { return SubPieces.end(); }
345 
flattenLocations()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;
begin()352   const_iterator begin() const { return SubPieces.begin(); }
end()353   const_iterator end() const { return SubPieces.end(); }
354 
classof(const PathDiagnosticPiece * P)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 
getDescription()381   llvm::StringRef getDescription() const { return Desc; }
getBugType()382   llvm::StringRef getBugType() const { return BugType; }
getCategory()383   llvm::StringRef getCategory() const { return Category; }
384 
385   typedef std::deque<std::string>::const_iterator meta_iterator;
meta_begin()386   meta_iterator meta_begin() const { return OtherDesc.begin(); }
meta_end()387   meta_iterator meta_end() const { return OtherDesc.end(); }
addMeta(llvm::StringRef s)388   void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); }
389 
getLocation()390   PathDiagnosticLocation getLocation() const {
391     assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
392     return rbegin()->getLocation();
393   }
394 
push_front(PathDiagnosticPiece * piece)395   void push_front(PathDiagnosticPiece* piece) {
396     assert(piece);
397     path.push_front(piece);
398     ++Size;
399   }
400 
push_back(PathDiagnosticPiece * piece)401   void push_back(PathDiagnosticPiece* piece) {
402     assert(piece);
403     path.push_back(piece);
404     ++Size;
405   }
406 
back()407   PathDiagnosticPiece* back() {
408     return path.back();
409   }
410 
back()411   const PathDiagnosticPiece* back() const {
412     return path.back();
413   }
414 
size()415   unsigned size() const { return Size; }
empty()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:
iterator(const ImplTy & i)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:
const_iterator(const ImplTy & i)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 
begin()477   iterator begin() { return path.begin(); }
end()478   iterator end() { return path.end(); }
479 
begin()480   const_iterator begin() const { return path.begin(); }
end()481   const_iterator end() const { return path.end(); }
482 
483   // reverse iterator creation methods.
rbegin()484   reverse_iterator rbegin()            { return reverse_iterator(end()); }
rbegin()485   const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
rend()486   reverse_iterator rend()              { return reverse_iterator(begin()); }
rend()487   const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
488 
flattenLocations()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
501