• 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/SourceLocation.h"
18 #include "clang/Analysis/ProgramPoint.h"
19 #include "llvm/ADT/FoldingSet.h"
20 #include "llvm/ADT/IntrusiveRefCntPtr.h"
21 #include "llvm/ADT/PointerUnion.h"
22 #include "llvm/ADT/Optional.h"
23 #include <deque>
24 #include <iterator>
25 #include <string>
26 #include <vector>
27 
28 namespace clang {
29 
30 class AnalysisDeclContext;
31 class BinaryOperator;
32 class CompoundStmt;
33 class Decl;
34 class LocationContext;
35 class MemberExpr;
36 class ParentMap;
37 class ProgramPoint;
38 class SourceManager;
39 class Stmt;
40 
41 namespace ento {
42 
43 class ExplodedNode;
44 class SymExpr;
45 typedef const SymExpr* SymbolRef;
46 
47 //===----------------------------------------------------------------------===//
48 // High-level interface for handlers of path-sensitive diagnostics.
49 //===----------------------------------------------------------------------===//
50 
51 class PathDiagnostic;
52 
53 class PathDiagnosticConsumer {
54   virtual void anchor();
55 public:
PathDiagnosticConsumer()56   PathDiagnosticConsumer() : flushed(false) {}
57   virtual ~PathDiagnosticConsumer();
58 
59   void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
60 
61   virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
62                                     SmallVectorImpl<std::string> *FilesMade)
63                                     = 0;
64 
65   virtual StringRef getName() const = 0;
66 
67   void HandlePathDiagnostic(PathDiagnostic *D);
68 
69   enum PathGenerationScheme { Minimal, Extensive };
getGenerationScheme()70   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
supportsLogicalOpControlFlow()71   virtual bool supportsLogicalOpControlFlow() const { return false; }
supportsAllBlockEdges()72   virtual bool supportsAllBlockEdges() const { return false; }
useVerboseDescription()73   virtual bool useVerboseDescription() const { return true; }
74 
75   /// Return true if the PathDiagnosticConsumer supports individual
76   /// PathDiagnostics that span multiple files.
supportsCrossFileDiagnostics()77   virtual bool supportsCrossFileDiagnostics() const { return false; }
78 
79 protected:
80   bool flushed;
81   llvm::FoldingSet<PathDiagnostic> Diags;
82 };
83 
84 //===----------------------------------------------------------------------===//
85 // Path-sensitive diagnostics.
86 //===----------------------------------------------------------------------===//
87 
88 class PathDiagnosticRange : public SourceRange {
89 public:
90   bool isPoint;
91 
92   PathDiagnosticRange(const SourceRange &R, bool isP = false)
SourceRange(R)93     : SourceRange(R), isPoint(isP) {}
94 
PathDiagnosticRange()95   PathDiagnosticRange() : isPoint(false) {}
96 };
97 
98 typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*>
99                                                    LocationOrAnalysisDeclContext;
100 
101 class PathDiagnosticLocation {
102 private:
103   enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
104   const Stmt *S;
105   const Decl *D;
106   const SourceManager *SM;
107   FullSourceLoc Loc;
108   PathDiagnosticRange Range;
109 
PathDiagnosticLocation(SourceLocation L,const SourceManager & sm,Kind kind)110   PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
111                          Kind kind)
112     : K(kind), S(0), D(0), SM(&sm),
113       Loc(genLocation(L)), Range(genRange()) {
114     assert(Loc.isValid());
115     assert(Range.isValid());
116   }
117 
118   FullSourceLoc
119     genLocation(SourceLocation L = SourceLocation(),
120                 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
121 
122   PathDiagnosticRange
123     genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
124 
125 public:
126   /// Create an invalid location.
PathDiagnosticLocation()127   PathDiagnosticLocation()
128     : K(SingleLocK), S(0), D(0), SM(0) {}
129 
130   /// Create a location corresponding to the given statement.
PathDiagnosticLocation(const Stmt * s,const SourceManager & sm,LocationOrAnalysisDeclContext lac)131   PathDiagnosticLocation(const Stmt *s,
132                          const SourceManager &sm,
133                          LocationOrAnalysisDeclContext lac)
134     : K(StmtK), S(s), D(0), SM(&sm),
135       Loc(genLocation(SourceLocation(), lac)),
136       Range(genRange(lac)) {
137     assert(S);
138     assert(Loc.isValid());
139     assert(Range.isValid());
140   }
141 
142   /// Create a location corresponding to the given declaration.
PathDiagnosticLocation(const Decl * d,const SourceManager & sm)143   PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
144     : K(DeclK), S(0), D(d), SM(&sm),
145       Loc(genLocation()), Range(genRange()) {
146     assert(D);
147     assert(Loc.isValid());
148     assert(Range.isValid());
149   }
150 
151   /// Create a location corresponding to the given declaration.
create(const Decl * D,const SourceManager & SM)152   static PathDiagnosticLocation create(const Decl *D,
153                                        const SourceManager &SM) {
154     return PathDiagnosticLocation(D, SM);
155   }
156 
157   /// Create a location for the beginning of the declaration.
158   static PathDiagnosticLocation createBegin(const Decl *D,
159                                             const SourceManager &SM);
160 
161   /// Create a location for the beginning of the statement.
162   static PathDiagnosticLocation createBegin(const Stmt *S,
163                                             const SourceManager &SM,
164                                             const LocationOrAnalysisDeclContext LAC);
165 
166   /// Create the location for the operator of the binary expression.
167   /// Assumes the statement has a valid location.
168   static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
169                                                   const SourceManager &SM);
170 
171   /// For member expressions, return the location of the '.' or '->'.
172   /// Assumes the statement has a valid location.
173   static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
174                                                 const SourceManager &SM);
175 
176   /// Create a location for the beginning of the compound statement.
177   /// Assumes the statement has a valid location.
178   static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
179                                                  const SourceManager &SM);
180 
181   /// Create a location for the end of the compound statement.
182   /// Assumes the statement has a valid location.
183   static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
184                                                const SourceManager &SM);
185 
186   /// Create a location for the beginning of the enclosing declaration body.
187   /// Defaults to the beginning of the first statement in the declaration body.
188   static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
189                                                 const SourceManager &SM);
190 
191   /// Constructs a location for the end of the enclosing declaration body.
192   /// Defaults to the end of brace.
193   static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
194                                                    const SourceManager &SM);
195 
196   /// Create a location corresponding to the given valid ExplodedNode.
197   static PathDiagnosticLocation create(const ProgramPoint& P,
198                                        const SourceManager &SMng);
199 
200   /// Create a location corresponding to the next valid ExplodedNode as end
201   /// of path location.
202   static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
203                                                 const SourceManager &SM);
204 
205   /// Convert the given location into a single kind location.
206   static PathDiagnosticLocation createSingleLocation(
207                                              const PathDiagnosticLocation &PDL);
208 
209   bool operator==(const PathDiagnosticLocation &X) const {
210     return K == X.K && Loc == X.Loc && Range == X.Range;
211   }
212 
213   bool operator!=(const PathDiagnosticLocation &X) const {
214     return !(*this == X);
215   }
216 
isValid()217   bool isValid() const {
218     return SM != 0;
219   }
220 
asLocation()221   FullSourceLoc asLocation() const {
222     return Loc;
223   }
224 
asRange()225   PathDiagnosticRange asRange() const {
226     return Range;
227   }
228 
asStmt()229   const Stmt *asStmt() const { assert(isValid()); return S; }
asDecl()230   const Decl *asDecl() const { assert(isValid()); return D; }
231 
hasRange()232   bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
233 
invalidate()234   void invalidate() {
235     *this = PathDiagnosticLocation();
236   }
237 
238   void flatten();
239 
getManager()240   const SourceManager& getManager() const { assert(isValid()); return *SM; }
241 
242   void Profile(llvm::FoldingSetNodeID &ID) const;
243 };
244 
245 class PathDiagnosticLocationPair {
246 private:
247   PathDiagnosticLocation Start, End;
248 public:
PathDiagnosticLocationPair(const PathDiagnosticLocation & start,const PathDiagnosticLocation & end)249   PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
250                              const PathDiagnosticLocation &end)
251     : Start(start), End(end) {}
252 
getStart()253   const PathDiagnosticLocation &getStart() const { return Start; }
getEnd()254   const PathDiagnosticLocation &getEnd() const { return End; }
255 
flatten()256   void flatten() {
257     Start.flatten();
258     End.flatten();
259   }
260 
Profile(llvm::FoldingSetNodeID & ID)261   void Profile(llvm::FoldingSetNodeID &ID) const {
262     Start.Profile(ID);
263     End.Profile(ID);
264   }
265 };
266 
267 //===----------------------------------------------------------------------===//
268 // Path "pieces" for path-sensitive diagnostics.
269 //===----------------------------------------------------------------------===//
270 
271 class PathDiagnosticPiece : public RefCountedBaseVPTR {
272 public:
273   enum Kind { ControlFlow, Event, Macro, Call };
274   enum DisplayHint { Above, Below };
275 
276 private:
277   const std::string str;
278   const Kind kind;
279   const DisplayHint Hint;
280   std::vector<SourceRange> ranges;
281 
282   // Do not implement:
283   PathDiagnosticPiece();
284   PathDiagnosticPiece(const PathDiagnosticPiece &P);
285   PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
286 
287 protected:
288   PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
289 
290   PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
291 
292 public:
293   virtual ~PathDiagnosticPiece();
294 
getString()295   const std::string& getString() const { return str; }
296 
297   /// getDisplayHint - Return a hint indicating where the diagnostic should
298   ///  be displayed by the PathDiagnosticConsumer.
getDisplayHint()299   DisplayHint getDisplayHint() const { return Hint; }
300 
301   virtual PathDiagnosticLocation getLocation() const = 0;
302   virtual void flattenLocations() = 0;
303 
getKind()304   Kind getKind() const { return kind; }
305 
addRange(SourceRange R)306   void addRange(SourceRange R) {
307     if (!R.isValid())
308       return;
309     ranges.push_back(R);
310   }
311 
addRange(SourceLocation B,SourceLocation E)312   void addRange(SourceLocation B, SourceLocation E) {
313     if (!B.isValid() || !E.isValid())
314       return;
315     ranges.push_back(SourceRange(B,E));
316   }
317 
318   typedef const SourceRange* range_iterator;
319 
ranges_begin()320   range_iterator ranges_begin() const {
321     return ranges.empty() ? NULL : &ranges[0];
322   }
323 
ranges_end()324   range_iterator ranges_end() const {
325     return ranges_begin() + ranges.size();
326   }
327 
classof(const PathDiagnosticPiece * P)328   static inline bool classof(const PathDiagnosticPiece *P) {
329     return true;
330   }
331 
332   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
333 };
334 
335 
336 class PathPieces :
337   public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
338 public:
339   ~PathPieces();
340 };
341 
342 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
343 private:
344   PathDiagnosticLocation Pos;
345 public:
346   PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
347                           StringRef s,
348                           PathDiagnosticPiece::Kind k,
349                           bool addPosRange = true)
PathDiagnosticPiece(s,k)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 
getLocation()356   PathDiagnosticLocation getLocation() const { return Pos; }
flattenLocations()357   virtual void flattenLocations() { Pos.flatten(); }
358 
359   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
360 };
361 
362 /// \brief Interface for classes constructing Stack hints.
363 ///
364 /// If a PathDiagnosticEvent occurs in a different frame than the final
365 /// diagnostic the hints can be used to summarise the effect of the call.
366 class StackHintGenerator {
367 public:
368   virtual ~StackHintGenerator() = 0;
369 
370   /// \brief Construct the Diagnostic message for the given ExplodedNode.
371   virtual std::string getMessage(const ExplodedNode *N) = 0;
372 };
373 
374 /// \brief Constructs a Stack hint for the given symbol.
375 ///
376 /// The class knows how to construct the stack hint message based on
377 /// traversing the CallExpr associated with the call and checking if the given
378 /// symbol is returned or is one of the arguments.
379 /// The hint can be customized by redefining 'getMessageForX()' methods.
380 class StackHintGeneratorForSymbol : public StackHintGenerator {
381 private:
382   SymbolRef Sym;
383   std::string Msg;
384 
385 public:
StackHintGeneratorForSymbol(SymbolRef S,StringRef M)386   StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
~StackHintGeneratorForSymbol()387   virtual ~StackHintGeneratorForSymbol() {}
388 
389   /// \brief Search the call expression for the symbol Sym and dispatch the
390   /// 'getMessageForX()' methods to construct a specific message.
391   virtual std::string getMessage(const ExplodedNode *N);
392 
393   /// Prints the ordinal form of the given integer,
394   /// only valid for ValNo : ValNo > 0.
395   void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out);
396 
397   /// Produces the message of the following form:
398   ///   'Msg via Nth parameter'
399   virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
getMessageForReturn(const CallExpr * CallExpr)400   virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
401     return Msg;
402   }
getMessageForSymbolNotFound()403   virtual std::string getMessageForSymbolNotFound() {
404     return Msg;
405   }
406 };
407 
408 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
409   llvm::Optional<bool> IsPrunable;
410 
411   /// If the event occurs in a different frame than the final diagnostic,
412   /// supply a message that will be used to construct an extra hint on the
413   /// returns from all the calls on the stack from this event to the final
414   /// diagnostic.
415   llvm::OwningPtr<StackHintGenerator> CallStackHint;
416 
417 public:
418   PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
419                            StringRef s, bool addPosRange = true,
420                            StackHintGenerator *stackHint = 0)
PathDiagnosticSpotPiece(pos,s,Event,addPosRange)421     : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
422       CallStackHint(stackHint) {}
423 
424   ~PathDiagnosticEventPiece();
425 
426   /// Mark the diagnostic piece as being potentially prunable.  This
427   /// flag may have been previously set, at which point it will not
428   /// be reset unless one specifies to do so.
429   void setPrunable(bool isPrunable, bool override = false) {
430     if (IsPrunable.hasValue() && !override)
431      return;
432     IsPrunable = isPrunable;
433   }
434 
435   /// Return true if the diagnostic piece is prunable.
isPrunable()436   bool isPrunable() const {
437     return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
438   }
439 
hasCallStackHint()440   bool hasCallStackHint() {
441     return (CallStackHint != 0);
442   }
443 
444   /// Produce the hint for the given node. The node contains
445   /// information about the call for which the diagnostic can be generated.
getCallStackMessage(const ExplodedNode * N)446   std::string getCallStackMessage(const ExplodedNode *N) {
447     if (CallStackHint)
448       return CallStackHint->getMessage(N);
449     return "";
450   }
451 
classof(const PathDiagnosticPiece * P)452   static inline bool classof(const PathDiagnosticPiece *P) {
453     return P->getKind() == Event;
454   }
455 };
456 
457 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
PathDiagnosticCallPiece(const Decl * callerD,const PathDiagnosticLocation & callReturnPos)458   PathDiagnosticCallPiece(const Decl *callerD,
459                           const PathDiagnosticLocation &callReturnPos)
460     : PathDiagnosticPiece(Call), Caller(callerD), Callee(0),
461       NoExit(false), callReturn(callReturnPos) {}
462 
PathDiagnosticCallPiece(PathPieces & oldPath,const Decl * caller)463   PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
464     : PathDiagnosticPiece(Call), Caller(caller), Callee(0),
465       NoExit(true), path(oldPath) {}
466 
467   const Decl *Caller;
468   const Decl *Callee;
469 
470   // Flag signifying that this diagnostic has only call enter and no matching
471   // call exit.
472   bool NoExit;
473 
474   // The custom string, which should appear after the call Return Diagnostic.
475   // TODO: Should we allow multiple diagnostics?
476   std::string CallStackMessage;
477 
478 public:
479   PathDiagnosticLocation callEnter;
480   PathDiagnosticLocation callEnterWithin;
481   PathDiagnosticLocation callReturn;
482   PathPieces path;
483 
484   virtual ~PathDiagnosticCallPiece();
485 
getCaller()486   const Decl *getCaller() const { return Caller; }
487 
getCallee()488   const Decl *getCallee() const { return Callee; }
489   void setCallee(const CallEnter &CE, const SourceManager &SM);
490 
hasCallStackMessage()491   bool hasCallStackMessage() { return !CallStackMessage.empty(); }
setCallStackMessage(StringRef st)492   void setCallStackMessage(StringRef st) {
493     CallStackMessage = st;
494   }
495 
getLocation()496   virtual PathDiagnosticLocation getLocation() const {
497     return callEnter;
498   }
499 
500   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const;
501   IntrusiveRefCntPtr<PathDiagnosticEventPiece>
502     getCallEnterWithinCallerEvent() const;
503   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const;
504 
flattenLocations()505   virtual void flattenLocations() {
506     callEnter.flatten();
507     callReturn.flatten();
508     for (PathPieces::iterator I = path.begin(),
509          E = path.end(); I != E; ++I) (*I)->flattenLocations();
510   }
511 
512   static PathDiagnosticCallPiece *construct(const ExplodedNode *N,
513                                             const CallExit &CE,
514                                             const SourceManager &SM);
515 
516   static PathDiagnosticCallPiece *construct(PathPieces &pieces,
517                                             const Decl *caller);
518 
519   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
520 
classof(const PathDiagnosticPiece * P)521   static inline bool classof(const PathDiagnosticPiece *P) {
522     return P->getKind() == Call;
523   }
524 };
525 
526 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
527   std::vector<PathDiagnosticLocationPair> LPairs;
528 public:
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation & startPos,const PathDiagnosticLocation & endPos,StringRef s)529   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
530                                  const PathDiagnosticLocation &endPos,
531                                  StringRef s)
532     : PathDiagnosticPiece(s, ControlFlow) {
533       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
534     }
535 
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation & startPos,const PathDiagnosticLocation & endPos)536   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
537                                  const PathDiagnosticLocation &endPos)
538     : PathDiagnosticPiece(ControlFlow) {
539       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
540     }
541 
542   ~PathDiagnosticControlFlowPiece();
543 
getStartLocation()544   PathDiagnosticLocation getStartLocation() const {
545     assert(!LPairs.empty() &&
546            "PathDiagnosticControlFlowPiece needs at least one location.");
547     return LPairs[0].getStart();
548   }
549 
getEndLocation()550   PathDiagnosticLocation getEndLocation() const {
551     assert(!LPairs.empty() &&
552            "PathDiagnosticControlFlowPiece needs at least one location.");
553     return LPairs[0].getEnd();
554   }
555 
push_back(const PathDiagnosticLocationPair & X)556   void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
557 
getLocation()558   virtual PathDiagnosticLocation getLocation() const {
559     return getStartLocation();
560   }
561 
562   typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
begin()563   iterator begin() { return LPairs.begin(); }
end()564   iterator end()   { return LPairs.end(); }
565 
flattenLocations()566   virtual void flattenLocations() {
567     for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
568   }
569 
570   typedef std::vector<PathDiagnosticLocationPair>::const_iterator
571           const_iterator;
begin()572   const_iterator begin() const { return LPairs.begin(); }
end()573   const_iterator end() const   { return LPairs.end(); }
574 
classof(const PathDiagnosticPiece * P)575   static inline bool classof(const PathDiagnosticPiece *P) {
576     return P->getKind() == ControlFlow;
577   }
578 
579   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
580 };
581 
582 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
583 public:
PathDiagnosticMacroPiece(const PathDiagnosticLocation & pos)584   PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
585     : PathDiagnosticSpotPiece(pos, "", Macro) {}
586 
587   ~PathDiagnosticMacroPiece();
588 
589   PathPieces subPieces;
590 
591   bool containsEvent() const;
592 
flattenLocations()593   virtual void flattenLocations() {
594     PathDiagnosticSpotPiece::flattenLocations();
595     for (PathPieces::iterator I = subPieces.begin(),
596          E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
597   }
598 
classof(const PathDiagnosticPiece * P)599   static inline bool classof(const PathDiagnosticPiece *P) {
600     return P->getKind() == Macro;
601   }
602 
603   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
604 };
605 
606 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
607 ///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
608 ///  each which represent the pieces of the path.
609 class PathDiagnostic : public llvm::FoldingSetNode {
610   const Decl *DeclWithIssue;
611   std::string BugType;
612   std::string Desc;
613   std::string Category;
614   std::deque<std::string> OtherDesc;
615   PathPieces pathImpl;
616   llvm::SmallVector<PathPieces *, 3> pathStack;
617 
618   PathDiagnostic(); // Do not implement.
619 public:
620   const PathPieces &path;
621 
622   /// Return the path currently used by builders for constructing the
623   /// PathDiagnostic.
getActivePath()624   PathPieces &getActivePath() {
625     if (pathStack.empty())
626       return pathImpl;
627     return *pathStack.back();
628   }
629 
630   /// Return a mutable version of 'path'.
getMutablePieces()631   PathPieces &getMutablePieces() {
632     return pathImpl;
633   }
634 
635   /// Return the unrolled size of the path.
636   unsigned full_size();
637 
pushActivePath(PathPieces * p)638   void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
popActivePath()639   void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
640 
641   //  PathDiagnostic();
642   PathDiagnostic(const Decl *DeclWithIssue,
643                  StringRef bugtype,
644                  StringRef desc,
645                  StringRef category);
646 
647   ~PathDiagnostic();
648 
getDescription()649   StringRef getDescription() const { return Desc; }
getBugType()650   StringRef getBugType() const { return BugType; }
getCategory()651   StringRef getCategory() const { return Category; }
652 
653   /// Return the semantic context where an issue occurred.  If the
654   /// issue occurs along a path, this represents the "central" area
655   /// where the bug manifests.
getDeclWithIssue()656   const Decl *getDeclWithIssue() const { return DeclWithIssue; }
657 
658   typedef std::deque<std::string>::const_iterator meta_iterator;
meta_begin()659   meta_iterator meta_begin() const { return OtherDesc.begin(); }
meta_end()660   meta_iterator meta_end() const { return OtherDesc.end(); }
addMeta(StringRef s)661   void addMeta(StringRef s) { OtherDesc.push_back(s); }
662 
663   PathDiagnosticLocation getLocation() const;
664 
flattenLocations()665   void flattenLocations() {
666     for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
667          I != E; ++I) (*I)->flattenLocations();
668   }
669 
670   void Profile(llvm::FoldingSetNodeID &ID) const;
671 
672   void FullProfile(llvm::FoldingSetNodeID &ID) const;
673 };
674 
675 } // end GR namespace
676 
677 } //end clang namespace
678 
679 #endif
680