]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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/Analysis/ProgramPoint.h"
18 #include "clang/Basic/SourceLocation.h"
19 #include "llvm/ADT/FoldingSet.h"
20 #include "llvm/ADT/IntrusiveRefCntPtr.h"
21 #include "llvm/ADT/Optional.h"
22 #include "llvm/ADT/PointerUnion.h"
23 #include <deque>
24 #include <list>
25 #include <iterator>
26 #include <string>
27 #include <vector>
28
29 namespace clang {
30
31 class AnalysisDeclContext;
32 class BinaryOperator;
33 class CompoundStmt;
34 class Decl;
35 class LocationContext;
36 class MemberExpr;
37 class ParentMap;
38 class ProgramPoint;
39 class SourceManager;
40 class Stmt;
41
42 namespace ento {
43
44 class ExplodedNode;
45 class SymExpr;
46 typedef const SymExpr* SymbolRef;
47
48 //===----------------------------------------------------------------------===//
49 // High-level interface for handlers of path-sensitive diagnostics.
50 //===----------------------------------------------------------------------===//
51
52 class PathDiagnostic;
53
54 class PathDiagnosticConsumer {
55 public:
56   class PDFileEntry : public llvm::FoldingSetNode {
57   public:
58     PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
59
60     typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles;
61     
62     /// \brief A vector of <consumer,file> pairs.
63     ConsumerFiles files;
64     
65     /// \brief A precomputed hash tag used for uniquing PDFileEntry objects.
66     const llvm::FoldingSetNodeID NodeID;
67
68     /// \brief Used for profiling in the FoldingSet.
69     void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
70   };
71   
72   struct FilesMade : public llvm::FoldingSet<PDFileEntry> {
73     llvm::BumpPtrAllocator Alloc;
74     
75     void addDiagnostic(const PathDiagnostic &PD,
76                        StringRef ConsumerName,
77                        StringRef fileName);
78     
79     PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
80   };
81
82 private:
83   virtual void anchor();
84 public:
85   PathDiagnosticConsumer() : flushed(false) {}
86   virtual ~PathDiagnosticConsumer();
87
88   void FlushDiagnostics(FilesMade *FilesMade);
89
90   virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
91                                     FilesMade *filesMade) = 0;
92
93   virtual StringRef getName() const = 0;
94   
95   void HandlePathDiagnostic(PathDiagnostic *D);
96
97   enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive };
98   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
99   virtual bool supportsLogicalOpControlFlow() const { return false; }
100   virtual bool supportsAllBlockEdges() const { return false; }
101   
102   /// Return true if the PathDiagnosticConsumer supports individual
103   /// PathDiagnostics that span multiple files.
104   virtual bool supportsCrossFileDiagnostics() const { return false; }
105
106 protected:
107   bool flushed;
108   llvm::FoldingSet<PathDiagnostic> Diags;
109 };
110
111 //===----------------------------------------------------------------------===//
112 // Path-sensitive diagnostics.
113 //===----------------------------------------------------------------------===//
114
115 class PathDiagnosticRange : public SourceRange {
116 public:
117   bool isPoint;
118
119   PathDiagnosticRange(const SourceRange &R, bool isP = false)
120     : SourceRange(R), isPoint(isP) {}
121
122   PathDiagnosticRange() : isPoint(false) {}
123 };
124
125 typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*>
126                                                    LocationOrAnalysisDeclContext;
127
128 class PathDiagnosticLocation {
129 private:
130   enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
131   const Stmt *S;
132   const Decl *D;
133   const SourceManager *SM;
134   FullSourceLoc Loc;
135   PathDiagnosticRange Range;
136
137   PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
138                          Kind kind)
139     : K(kind), S(0), D(0), SM(&sm),
140       Loc(genLocation(L)), Range(genRange()) {
141   }
142
143   FullSourceLoc
144     genLocation(SourceLocation L = SourceLocation(),
145                 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
146
147   PathDiagnosticRange
148     genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
149
150 public:
151   /// Create an invalid location.
152   PathDiagnosticLocation()
153     : K(SingleLocK), S(0), D(0), SM(0) {}
154
155   /// Create a location corresponding to the given statement.
156   PathDiagnosticLocation(const Stmt *s,
157                          const SourceManager &sm,
158                          LocationOrAnalysisDeclContext lac)
159     : K(s->getLocStart().isValid() ? StmtK : SingleLocK),
160       S(K == StmtK ? s : 0),
161       D(0), SM(&sm),
162       Loc(genLocation(SourceLocation(), lac)),
163       Range(genRange(lac)) {
164     assert(K == SingleLocK || S);
165     assert(K == SingleLocK || Loc.isValid());
166     assert(K == SingleLocK || Range.isValid());
167   }
168
169   /// Create a location corresponding to the given declaration.
170   PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
171     : K(DeclK), S(0), D(d), SM(&sm),
172       Loc(genLocation()), Range(genRange()) {
173     assert(D);
174     assert(Loc.isValid());
175     assert(Range.isValid());
176   }
177
178   /// Create a location at an explicit offset in the source.
179   ///
180   /// This should only be used if there are no more appropriate constructors.
181   PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
182     : K(SingleLocK), S(0), D(0), SM(&sm), Loc(loc, sm), Range(genRange()) {
183     assert(Loc.isValid());
184     assert(Range.isValid());
185   }
186
187   /// Create a location corresponding to the given declaration.
188   static PathDiagnosticLocation create(const Decl *D,
189                                        const SourceManager &SM) {
190     return PathDiagnosticLocation(D, SM);
191   }
192
193   /// Create a location for the beginning of the declaration.
194   static PathDiagnosticLocation createBegin(const Decl *D,
195                                             const SourceManager &SM);
196
197   /// Create a location for the beginning of the statement.
198   static PathDiagnosticLocation createBegin(const Stmt *S,
199                                             const SourceManager &SM,
200                                             const LocationOrAnalysisDeclContext LAC);
201
202   /// Create a location for the end of the statement.
203   ///
204   /// If the statement is a CompoundStatement, the location will point to the
205   /// closing brace instead of following it.
206   static PathDiagnosticLocation createEnd(const Stmt *S,
207                                           const SourceManager &SM,
208                                        const LocationOrAnalysisDeclContext LAC);
209
210   /// Create the location for the operator of the binary expression.
211   /// Assumes the statement has a valid location.
212   static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
213                                                   const SourceManager &SM);
214
215   /// For member expressions, return the location of the '.' or '->'.
216   /// Assumes the statement has a valid location.
217   static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
218                                                 const SourceManager &SM);
219
220   /// Create a location for the beginning of the compound statement.
221   /// Assumes the statement has a valid location.
222   static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
223                                                  const SourceManager &SM);
224
225   /// Create a location for the end of the compound statement.
226   /// Assumes the statement has a valid location.
227   static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
228                                                const SourceManager &SM);
229
230   /// Create a location for the beginning of the enclosing declaration body.
231   /// Defaults to the beginning of the first statement in the declaration body.
232   static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
233                                                 const SourceManager &SM);
234
235   /// Constructs a location for the end of the enclosing declaration body.
236   /// Defaults to the end of brace.
237   static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
238                                                    const SourceManager &SM);
239
240   /// Create a location corresponding to the given valid ExplodedNode.
241   static PathDiagnosticLocation create(const ProgramPoint& P,
242                                        const SourceManager &SMng);
243
244   /// Create a location corresponding to the next valid ExplodedNode as end
245   /// of path location.
246   static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
247                                                 const SourceManager &SM);
248
249   /// Convert the given location into a single kind location.
250   static PathDiagnosticLocation createSingleLocation(
251                                              const PathDiagnosticLocation &PDL);
252
253   bool operator==(const PathDiagnosticLocation &X) const {
254     return K == X.K && Loc == X.Loc && Range == X.Range;
255   }
256
257   bool operator!=(const PathDiagnosticLocation &X) const {
258     return !(*this == X);
259   }
260
261   bool isValid() const {
262     return SM != 0;
263   }
264
265   FullSourceLoc asLocation() const {
266     return Loc;
267   }
268
269   PathDiagnosticRange asRange() const {
270     return Range;
271   }
272
273   const Stmt *asStmt() const { assert(isValid()); return S; }
274   const Decl *asDecl() const { assert(isValid()); return D; }
275
276   bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
277
278   void invalidate() {
279     *this = PathDiagnosticLocation();
280   }
281
282   void flatten();
283
284   const SourceManager& getManager() const { assert(isValid()); return *SM; }
285   
286   void Profile(llvm::FoldingSetNodeID &ID) const;
287
288   /// \brief Given an exploded node, retrieve the statement that should be used 
289   /// for the diagnostic location.
290   static const Stmt *getStmt(const ExplodedNode *N);
291
292   /// \brief Retrieve the statement corresponding to the sucessor node.
293   static const Stmt *getNextStmt(const ExplodedNode *N);
294 };
295
296 class PathDiagnosticLocationPair {
297 private:
298   PathDiagnosticLocation Start, End;
299 public:
300   PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
301                              const PathDiagnosticLocation &end)
302     : Start(start), End(end) {}
303
304   const PathDiagnosticLocation &getStart() const { return Start; }
305   const PathDiagnosticLocation &getEnd() const { return End; }
306
307   void setStart(const PathDiagnosticLocation &L) { Start = L; }
308   void setEnd(const PathDiagnosticLocation &L) { End = L; }
309
310   void flatten() {
311     Start.flatten();
312     End.flatten();
313   }
314   
315   void Profile(llvm::FoldingSetNodeID &ID) const {
316     Start.Profile(ID);
317     End.Profile(ID);
318   }
319 };
320
321 //===----------------------------------------------------------------------===//
322 // Path "pieces" for path-sensitive diagnostics.
323 //===----------------------------------------------------------------------===//
324
325 class PathDiagnosticPiece : public RefCountedBaseVPTR {
326 public:
327   enum Kind { ControlFlow, Event, Macro, Call };
328   enum DisplayHint { Above, Below };
329
330 private:
331   const std::string str;
332   const Kind kind;
333   const DisplayHint Hint;
334   
335   /// A constant string that can be used to tag the PathDiagnosticPiece,
336   /// typically with the identification of the creator.  The actual pointer
337   /// value is meant to be an identifier; the string itself is useful for
338   /// debugging.
339   StringRef Tag;
340
341   std::vector<SourceRange> ranges;
342
343   PathDiagnosticPiece() LLVM_DELETED_FUNCTION;
344   PathDiagnosticPiece(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION;
345   void operator=(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION;
346
347 protected:
348   PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
349
350   PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
351
352 public:
353   virtual ~PathDiagnosticPiece();
354
355   StringRef getString() const { return str; }
356
357   /// Tag this PathDiagnosticPiece with the given C-string.
358   void setTag(const char *tag) { Tag = tag; }
359   
360   /// Return the opaque tag (if any) on the PathDiagnosticPiece.
361   const void *getTag() const { return Tag.data(); }
362   
363   /// Return the string representation of the tag.  This is useful
364   /// for debugging.
365   StringRef getTagStr() const { return Tag; }
366   
367   /// getDisplayHint - Return a hint indicating where the diagnostic should
368   ///  be displayed by the PathDiagnosticConsumer.
369   DisplayHint getDisplayHint() const { return Hint; }
370
371   virtual PathDiagnosticLocation getLocation() const = 0;
372   virtual void flattenLocations() = 0;
373
374   Kind getKind() const { return kind; }
375
376   void addRange(SourceRange R) {
377     if (!R.isValid())
378       return;
379     ranges.push_back(R);
380   }
381
382   void addRange(SourceLocation B, SourceLocation E) {
383     if (!B.isValid() || !E.isValid())
384       return;
385     ranges.push_back(SourceRange(B,E));
386   }
387
388   /// Return the SourceRanges associated with this PathDiagnosticPiece.
389   ArrayRef<SourceRange> getRanges() const { return ranges; }
390
391   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
392 };
393   
394   
395 class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
396   void flattenTo(PathPieces &Primary, PathPieces &Current,
397                  bool ShouldFlattenMacros) const;
398 public:
399   ~PathPieces();
400
401   PathPieces flatten(bool ShouldFlattenMacros) const {
402     PathPieces Result;
403     flattenTo(Result, Result, ShouldFlattenMacros);
404     return Result;
405   }
406 };
407
408 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
409 private:
410   PathDiagnosticLocation Pos;
411 public:
412   PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
413                           StringRef s,
414                           PathDiagnosticPiece::Kind k,
415                           bool addPosRange = true)
416   : PathDiagnosticPiece(s, k), Pos(pos) {
417     assert(Pos.isValid() && Pos.asLocation().isValid() &&
418            "PathDiagnosticSpotPiece's must have a valid location.");
419     if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
420   }
421
422   PathDiagnosticLocation getLocation() const { return Pos; }
423   virtual void flattenLocations() { Pos.flatten(); }
424   
425   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
426
427   static bool classof(const PathDiagnosticPiece *P) {
428     return P->getKind() == Event || P->getKind() == Macro;
429   }
430 };
431
432 /// \brief Interface for classes constructing Stack hints.
433 ///
434 /// If a PathDiagnosticEvent occurs in a different frame than the final 
435 /// diagnostic the hints can be used to summarize the effect of the call.
436 class StackHintGenerator {
437 public:
438   virtual ~StackHintGenerator() = 0;
439
440   /// \brief Construct the Diagnostic message for the given ExplodedNode.
441   virtual std::string getMessage(const ExplodedNode *N) = 0;
442 };
443
444 /// \brief Constructs a Stack hint for the given symbol.
445 ///
446 /// The class knows how to construct the stack hint message based on
447 /// traversing the CallExpr associated with the call and checking if the given
448 /// symbol is returned or is one of the arguments.
449 /// The hint can be customized by redefining 'getMessageForX()' methods.
450 class StackHintGeneratorForSymbol : public StackHintGenerator {
451 private:
452   SymbolRef Sym;
453   std::string Msg;
454
455 public:
456   StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
457   virtual ~StackHintGeneratorForSymbol() {}
458
459   /// \brief Search the call expression for the symbol Sym and dispatch the
460   /// 'getMessageForX()' methods to construct a specific message.
461   virtual std::string getMessage(const ExplodedNode *N);
462
463   /// Produces the message of the following form:
464   ///   'Msg via Nth parameter'
465   virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
466   virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
467     return Msg;
468   }
469   virtual std::string getMessageForSymbolNotFound() {
470     return Msg;
471   }
472 };
473
474 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
475   Optional<bool> IsPrunable;
476
477   /// If the event occurs in a different frame than the final diagnostic,
478   /// supply a message that will be used to construct an extra hint on the
479   /// returns from all the calls on the stack from this event to the final
480   /// diagnostic.
481   OwningPtr<StackHintGenerator> CallStackHint;
482
483 public:
484   PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
485                            StringRef s, bool addPosRange = true,
486                            StackHintGenerator *stackHint = 0)
487     : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
488       CallStackHint(stackHint) {}
489
490   ~PathDiagnosticEventPiece();
491
492   /// Mark the diagnostic piece as being potentially prunable.  This
493   /// flag may have been previously set, at which point it will not
494   /// be reset unless one specifies to do so.
495   void setPrunable(bool isPrunable, bool override = false) {
496     if (IsPrunable.hasValue() && !override)
497      return;
498     IsPrunable = isPrunable;
499   }
500
501   /// Return true if the diagnostic piece is prunable.
502   bool isPrunable() const {
503     return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
504   }
505   
506   bool hasCallStackHint() {
507     return (CallStackHint != 0);
508   }
509
510   /// Produce the hint for the given node. The node contains 
511   /// information about the call for which the diagnostic can be generated.
512   std::string getCallStackMessage(const ExplodedNode *N) {
513     if (CallStackHint)
514       return CallStackHint->getMessage(N);
515     return "";  
516   }
517
518   static inline bool classof(const PathDiagnosticPiece *P) {
519     return P->getKind() == Event;
520   }
521 };
522
523 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
524   PathDiagnosticCallPiece(const Decl *callerD,
525                           const PathDiagnosticLocation &callReturnPos)
526     : PathDiagnosticPiece(Call), Caller(callerD), Callee(0),
527       NoExit(false), callReturn(callReturnPos) {}
528
529   PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
530     : PathDiagnosticPiece(Call), Caller(caller), Callee(0),
531       NoExit(true), path(oldPath) {}
532   
533   const Decl *Caller;
534   const Decl *Callee;
535
536   // Flag signifying that this diagnostic has only call enter and no matching
537   // call exit.
538   bool NoExit;
539
540   // The custom string, which should appear after the call Return Diagnostic.
541   // TODO: Should we allow multiple diagnostics?
542   std::string CallStackMessage;
543
544 public:
545   PathDiagnosticLocation callEnter;
546   PathDiagnosticLocation callEnterWithin;
547   PathDiagnosticLocation callReturn;  
548   PathPieces path;
549   
550   virtual ~PathDiagnosticCallPiece();
551   
552   const Decl *getCaller() const { return Caller; }
553   
554   const Decl *getCallee() const { return Callee; }
555   void setCallee(const CallEnter &CE, const SourceManager &SM);
556   
557   bool hasCallStackMessage() { return !CallStackMessage.empty(); }
558   void setCallStackMessage(StringRef st) {
559     CallStackMessage = st;
560   }
561
562   virtual PathDiagnosticLocation getLocation() const {
563     return callEnter;
564   }
565   
566   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const;
567   IntrusiveRefCntPtr<PathDiagnosticEventPiece>
568     getCallEnterWithinCallerEvent() const;
569   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const;
570
571   virtual void flattenLocations() {
572     callEnter.flatten();
573     callReturn.flatten();
574     for (PathPieces::iterator I = path.begin(), 
575          E = path.end(); I != E; ++I) (*I)->flattenLocations();
576   }
577   
578   static PathDiagnosticCallPiece *construct(const ExplodedNode *N,
579                                             const CallExitEnd &CE,
580                                             const SourceManager &SM);
581   
582   static PathDiagnosticCallPiece *construct(PathPieces &pieces,
583                                             const Decl *caller);
584   
585   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
586
587   static inline bool classof(const PathDiagnosticPiece *P) {
588     return P->getKind() == Call;
589   }
590 };
591
592 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
593   std::vector<PathDiagnosticLocationPair> LPairs;
594 public:
595   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
596                                  const PathDiagnosticLocation &endPos,
597                                  StringRef s)
598     : PathDiagnosticPiece(s, ControlFlow) {
599       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
600     }
601
602   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
603                                  const PathDiagnosticLocation &endPos)
604     : PathDiagnosticPiece(ControlFlow) {
605       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
606     }
607
608   ~PathDiagnosticControlFlowPiece();
609
610   PathDiagnosticLocation getStartLocation() const {
611     assert(!LPairs.empty() &&
612            "PathDiagnosticControlFlowPiece needs at least one location.");
613     return LPairs[0].getStart();
614   }
615
616   PathDiagnosticLocation getEndLocation() const {
617     assert(!LPairs.empty() &&
618            "PathDiagnosticControlFlowPiece needs at least one location.");
619     return LPairs[0].getEnd();
620   }
621
622   void setStartLocation(const PathDiagnosticLocation &L) {
623     LPairs[0].setStart(L);
624   }
625
626   void setEndLocation(const PathDiagnosticLocation &L) {
627     LPairs[0].setEnd(L);
628   }
629
630   void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
631
632   virtual PathDiagnosticLocation getLocation() const {
633     return getStartLocation();
634   }
635
636   typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
637   iterator begin() { return LPairs.begin(); }
638   iterator end()   { return LPairs.end(); }
639
640   virtual void flattenLocations() {
641     for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
642   }
643
644   typedef std::vector<PathDiagnosticLocationPair>::const_iterator
645           const_iterator;
646   const_iterator begin() const { return LPairs.begin(); }
647   const_iterator end() const   { return LPairs.end(); }
648
649   static inline bool classof(const PathDiagnosticPiece *P) {
650     return P->getKind() == ControlFlow;
651   }
652   
653   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
654 };
655
656 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
657 public:
658   PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
659     : PathDiagnosticSpotPiece(pos, "", Macro) {}
660
661   ~PathDiagnosticMacroPiece();
662
663   PathPieces subPieces;
664   
665   bool containsEvent() const;
666
667   virtual void flattenLocations() {
668     PathDiagnosticSpotPiece::flattenLocations();
669     for (PathPieces::iterator I = subPieces.begin(), 
670          E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
671   }
672
673   static inline bool classof(const PathDiagnosticPiece *P) {
674     return P->getKind() == Macro;
675   }
676   
677   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
678 };
679
680 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
681 ///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
682 ///  each which represent the pieces of the path.
683 class PathDiagnostic : public llvm::FoldingSetNode {
684   const Decl *DeclWithIssue;
685   std::string BugType;
686   std::string VerboseDesc;
687   std::string ShortDesc;
688   std::string Category;
689   std::deque<std::string> OtherDesc;
690   PathDiagnosticLocation Loc;
691   PathPieces pathImpl;
692   SmallVector<PathPieces *, 3> pathStack;
693   
694   /// \brief Important bug uniqueing location.
695   /// The location info is useful to differentiate between bugs.
696   PathDiagnosticLocation UniqueingLoc;
697   const Decl *UniqueingDecl;
698
699   PathDiagnostic() LLVM_DELETED_FUNCTION;
700 public:
701   PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype,
702                  StringRef verboseDesc, StringRef shortDesc,
703                  StringRef category, PathDiagnosticLocation LocationToUnique,
704                  const Decl *DeclToUnique);
705
706   ~PathDiagnostic();
707   
708   const PathPieces &path;
709
710   /// Return the path currently used by builders for constructing the 
711   /// PathDiagnostic.
712   PathPieces &getActivePath() {
713     if (pathStack.empty())
714       return pathImpl;
715     return *pathStack.back();
716   }
717   
718   /// Return a mutable version of 'path'.
719   PathPieces &getMutablePieces() {
720     return pathImpl;
721   }
722     
723   /// Return the unrolled size of the path.
724   unsigned full_size();
725
726   void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
727   void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
728
729   bool isWithinCall() const { return !pathStack.empty(); }
730
731   void setEndOfPath(PathDiagnosticPiece *EndPiece) {
732     assert(!Loc.isValid() && "End location already set!");
733     Loc = EndPiece->getLocation();
734     assert(Loc.isValid() && "Invalid location for end-of-path piece");
735     getActivePath().push_back(EndPiece);
736   }
737
738   void resetPath() {
739     pathStack.clear();
740     pathImpl.clear();
741     Loc = PathDiagnosticLocation();
742   }
743   
744   StringRef getVerboseDescription() const { return VerboseDesc; }
745   StringRef getShortDescription() const {
746     return ShortDesc.empty() ? VerboseDesc : ShortDesc;
747   }
748   StringRef getBugType() const { return BugType; }
749   StringRef getCategory() const { return Category; }
750
751   /// Return the semantic context where an issue occurred.  If the
752   /// issue occurs along a path, this represents the "central" area
753   /// where the bug manifests.
754   const Decl *getDeclWithIssue() const { return DeclWithIssue; }
755
756   typedef std::deque<std::string>::const_iterator meta_iterator;
757   meta_iterator meta_begin() const { return OtherDesc.begin(); }
758   meta_iterator meta_end() const { return OtherDesc.end(); }
759   void addMeta(StringRef s) { OtherDesc.push_back(s); }
760
761   PathDiagnosticLocation getLocation() const {
762     assert(Loc.isValid() && "No end-of-path location set yet!");
763     return Loc;
764   }
765
766   /// \brief Get the location on which the report should be uniqued.
767   PathDiagnosticLocation getUniqueingLoc() const {
768     return UniqueingLoc;
769   }
770
771   /// \brief Get the declaration containing the uniqueing location.
772   const Decl *getUniqueingDecl() const {
773     return UniqueingDecl;
774   }
775
776   void flattenLocations() {
777     Loc.flatten();
778     for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); 
779          I != E; ++I) (*I)->flattenLocations();
780   }
781
782   /// Profiles the diagnostic, independent of the path it references.
783   ///
784   /// This can be used to merge diagnostics that refer to the same issue
785   /// along different paths.
786   void Profile(llvm::FoldingSetNodeID &ID) const;
787
788   /// Profiles the diagnostic, including its path.
789   ///
790   /// Two diagnostics with the same issue along different paths will generate
791   /// different profiles.
792   void FullProfile(llvm::FoldingSetNodeID &ID) const;
793 };  
794
795 } // end GR namespace
796
797 } //end clang namespace
798
799 #endif