clang API Documentation

PathDiagnostic.h
Go to the documentation of this file.
00001 //===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines the PathDiagnostic-related interfaces.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
00015 #define LLVM_CLANG_PATH_DIAGNOSTIC_H
00016 
00017 #include "clang/Basic/SourceLocation.h"
00018 #include "clang/Analysis/ProgramPoint.h"
00019 #include "llvm/ADT/FoldingSet.h"
00020 #include "llvm/ADT/IntrusiveRefCntPtr.h"
00021 #include "llvm/ADT/PointerUnion.h"
00022 #include "llvm/ADT/Optional.h"
00023 #include <deque>
00024 #include <iterator>
00025 #include <string>
00026 #include <vector>
00027 
00028 namespace clang {
00029 
00030 class AnalysisDeclContext;
00031 class BinaryOperator;
00032 class CompoundStmt;
00033 class Decl;
00034 class LocationContext;
00035 class MemberExpr;
00036 class ParentMap;
00037 class ProgramPoint;
00038 class SourceManager;
00039 class Stmt;
00040 
00041 namespace ento {
00042 
00043 class ExplodedNode;
00044 class SymExpr;
00045 typedef const SymExpr* SymbolRef;
00046 
00047 //===----------------------------------------------------------------------===//
00048 // High-level interface for handlers of path-sensitive diagnostics.
00049 //===----------------------------------------------------------------------===//
00050 
00051 class PathDiagnostic;
00052 
00053 class PathDiagnosticConsumer {
00054   virtual void anchor();
00055 public:
00056   PathDiagnosticConsumer() : flushed(false) {}
00057   virtual ~PathDiagnosticConsumer();
00058 
00059   void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
00060 
00061   virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
00062                                     SmallVectorImpl<std::string> *FilesMade)
00063                                     = 0;
00064 
00065   virtual StringRef getName() const = 0;
00066   
00067   void HandlePathDiagnostic(PathDiagnostic *D);
00068 
00069   enum PathGenerationScheme { Minimal, Extensive };
00070   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
00071   virtual bool supportsLogicalOpControlFlow() const { return false; }
00072   virtual bool supportsAllBlockEdges() const { return false; }
00073   virtual bool useVerboseDescription() const { return true; }
00074   
00075   /// Return true if the PathDiagnosticConsumer supports individual
00076   /// PathDiagnostics that span multiple files.
00077   virtual bool supportsCrossFileDiagnostics() const { return false; }
00078 
00079 protected:
00080   bool flushed;
00081   llvm::FoldingSet<PathDiagnostic> Diags;
00082 };
00083 
00084 //===----------------------------------------------------------------------===//
00085 // Path-sensitive diagnostics.
00086 //===----------------------------------------------------------------------===//
00087 
00088 class PathDiagnosticRange : public SourceRange {
00089 public:
00090   bool isPoint;
00091 
00092   PathDiagnosticRange(const SourceRange &R, bool isP = false)
00093     : SourceRange(R), isPoint(isP) {}
00094 
00095   PathDiagnosticRange() : isPoint(false) {}
00096 };
00097 
00098 typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*>
00099                                                    LocationOrAnalysisDeclContext;
00100 
00101 class PathDiagnosticLocation {
00102 private:
00103   enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
00104   const Stmt *S;
00105   const Decl *D;
00106   const SourceManager *SM;
00107   FullSourceLoc Loc;
00108   PathDiagnosticRange Range;
00109 
00110   PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
00111                          Kind kind)
00112     : K(kind), S(0), D(0), SM(&sm),
00113       Loc(genLocation(L)), Range(genRange()) {
00114     assert(Loc.isValid());
00115     assert(Range.isValid());
00116   }
00117 
00118   FullSourceLoc
00119     genLocation(SourceLocation L = SourceLocation(),
00120                 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
00121 
00122   PathDiagnosticRange
00123     genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
00124 
00125 public:
00126   /// Create an invalid location.
00127   PathDiagnosticLocation()
00128     : K(SingleLocK), S(0), D(0), SM(0) {}
00129 
00130   /// Create a location corresponding to the given statement.
00131   PathDiagnosticLocation(const Stmt *s,
00132                          const SourceManager &sm,
00133                          LocationOrAnalysisDeclContext lac)
00134     : K(StmtK), S(s), D(0), SM(&sm),
00135       Loc(genLocation(SourceLocation(), lac)),
00136       Range(genRange(lac)) {
00137     assert(S);
00138     assert(Loc.isValid());
00139     assert(Range.isValid());
00140   }
00141 
00142   /// Create a location corresponding to the given declaration.
00143   PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
00144     : K(DeclK), S(0), D(d), SM(&sm),
00145       Loc(genLocation()), Range(genRange()) {
00146     assert(D);
00147     assert(Loc.isValid());
00148     assert(Range.isValid());
00149   }
00150 
00151   /// Create a location corresponding to the given declaration.
00152   static PathDiagnosticLocation create(const Decl *D,
00153                                        const SourceManager &SM) {
00154     return PathDiagnosticLocation(D, SM);
00155   }
00156 
00157   /// Create a location for the beginning of the declaration.
00158   static PathDiagnosticLocation createBegin(const Decl *D,
00159                                             const SourceManager &SM);
00160 
00161   /// Create a location for the beginning of the statement.
00162   static PathDiagnosticLocation createBegin(const Stmt *S,
00163                                             const SourceManager &SM,
00164                                             const LocationOrAnalysisDeclContext LAC);
00165 
00166   /// Create the location for the operator of the binary expression.
00167   /// Assumes the statement has a valid location.
00168   static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
00169                                                   const SourceManager &SM);
00170 
00171   /// For member expressions, return the location of the '.' or '->'.
00172   /// Assumes the statement has a valid location.
00173   static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
00174                                                 const SourceManager &SM);
00175 
00176   /// Create a location for the beginning of the compound statement.
00177   /// Assumes the statement has a valid location.
00178   static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
00179                                                  const SourceManager &SM);
00180 
00181   /// Create a location for the end of the compound statement.
00182   /// Assumes the statement has a valid location.
00183   static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
00184                                                const SourceManager &SM);
00185 
00186   /// Create a location for the beginning of the enclosing declaration body.
00187   /// Defaults to the beginning of the first statement in the declaration body.
00188   static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
00189                                                 const SourceManager &SM);
00190 
00191   /// Constructs a location for the end of the enclosing declaration body.
00192   /// Defaults to the end of brace.
00193   static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
00194                                                    const SourceManager &SM);
00195 
00196   /// Create a location corresponding to the given valid ExplodedNode.
00197   static PathDiagnosticLocation create(const ProgramPoint& P,
00198                                        const SourceManager &SMng);
00199 
00200   /// Create a location corresponding to the next valid ExplodedNode as end
00201   /// of path location.
00202   static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
00203                                                 const SourceManager &SM);
00204 
00205   /// Convert the given location into a single kind location.
00206   static PathDiagnosticLocation createSingleLocation(
00207                                              const PathDiagnosticLocation &PDL);
00208 
00209   bool operator==(const PathDiagnosticLocation &X) const {
00210     return K == X.K && Loc == X.Loc && Range == X.Range;
00211   }
00212 
00213   bool operator!=(const PathDiagnosticLocation &X) const {
00214     return !(*this == X);
00215   }
00216 
00217   bool isValid() const {
00218     return SM != 0;
00219   }
00220 
00221   FullSourceLoc asLocation() const {
00222     return Loc;
00223   }
00224 
00225   PathDiagnosticRange asRange() const {
00226     return Range;
00227   }
00228 
00229   const Stmt *asStmt() const { assert(isValid()); return S; }
00230   const Decl *asDecl() const { assert(isValid()); return D; }
00231 
00232   bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
00233 
00234   void invalidate() {
00235     *this = PathDiagnosticLocation();
00236   }
00237 
00238   void flatten();
00239 
00240   const SourceManager& getManager() const { assert(isValid()); return *SM; }
00241   
00242   void Profile(llvm::FoldingSetNodeID &ID) const;
00243 };
00244 
00245 class PathDiagnosticLocationPair {
00246 private:
00247   PathDiagnosticLocation Start, End;
00248 public:
00249   PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
00250                              const PathDiagnosticLocation &end)
00251     : Start(start), End(end) {}
00252 
00253   const PathDiagnosticLocation &getStart() const { return Start; }
00254   const PathDiagnosticLocation &getEnd() const { return End; }
00255 
00256   void flatten() {
00257     Start.flatten();
00258     End.flatten();
00259   }
00260   
00261   void Profile(llvm::FoldingSetNodeID &ID) const {
00262     Start.Profile(ID);
00263     End.Profile(ID);
00264   }
00265 };
00266 
00267 //===----------------------------------------------------------------------===//
00268 // Path "pieces" for path-sensitive diagnostics.
00269 //===----------------------------------------------------------------------===//
00270 
00271 class PathDiagnosticPiece : public RefCountedBaseVPTR {
00272 public:
00273   enum Kind { ControlFlow, Event, Macro, Call };
00274   enum DisplayHint { Above, Below };
00275 
00276 private:
00277   const std::string str;
00278   const Kind kind;
00279   const DisplayHint Hint;
00280   std::vector<SourceRange> ranges;
00281 
00282   // Do not implement:
00283   PathDiagnosticPiece();
00284   PathDiagnosticPiece(const PathDiagnosticPiece &P);
00285   PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
00286 
00287 protected:
00288   PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
00289 
00290   PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
00291 
00292 public:
00293   virtual ~PathDiagnosticPiece();
00294 
00295   const std::string& getString() const { return str; }
00296 
00297   /// getDisplayHint - Return a hint indicating where the diagnostic should
00298   ///  be displayed by the PathDiagnosticConsumer.
00299   DisplayHint getDisplayHint() const { return Hint; }
00300 
00301   virtual PathDiagnosticLocation getLocation() const = 0;
00302   virtual void flattenLocations() = 0;
00303 
00304   Kind getKind() const { return kind; }
00305 
00306   void addRange(SourceRange R) {
00307     if (!R.isValid())
00308       return;
00309     ranges.push_back(R);
00310   }
00311 
00312   void addRange(SourceLocation B, SourceLocation E) {
00313     if (!B.isValid() || !E.isValid())
00314       return;
00315     ranges.push_back(SourceRange(B,E));
00316   }
00317 
00318   typedef const SourceRange* range_iterator;
00319 
00320   range_iterator ranges_begin() const {
00321     return ranges.empty() ? NULL : &ranges[0];
00322   }
00323 
00324   range_iterator ranges_end() const {
00325     return ranges_begin() + ranges.size();
00326   }
00327 
00328   static inline bool classof(const PathDiagnosticPiece *P) {
00329     return true;
00330   }
00331   
00332   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
00333 };
00334   
00335   
00336 class PathPieces :
00337   public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
00338 public:
00339   ~PathPieces();  
00340 };
00341 
00342 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
00343 private:
00344   PathDiagnosticLocation Pos;
00345 public:
00346   PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
00347                           StringRef s,
00348                           PathDiagnosticPiece::Kind k,
00349                           bool addPosRange = true)
00350   : PathDiagnosticPiece(s, k), Pos(pos) {
00351     assert(Pos.isValid() && Pos.asLocation().isValid() &&
00352            "PathDiagnosticSpotPiece's must have a valid location.");
00353     if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
00354   }
00355 
00356   PathDiagnosticLocation getLocation() const { return Pos; }
00357   virtual void flattenLocations() { Pos.flatten(); }
00358   
00359   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
00360 };
00361 
00362 /// \brief Interface for classes constructing Stack hints.
00363 ///
00364 /// If a PathDiagnosticEvent occurs in a different frame than the final 
00365 /// diagnostic the hints can be used to summarize the effect of the call.
00366 class StackHintGenerator {
00367 public:
00368   virtual ~StackHintGenerator() = 0;
00369 
00370   /// \brief Construct the Diagnostic message for the given ExplodedNode.
00371   virtual std::string getMessage(const ExplodedNode *N) = 0;
00372 };
00373 
00374 /// \brief Constructs a Stack hint for the given symbol.
00375 ///
00376 /// The class knows how to construct the stack hint message based on
00377 /// traversing the CallExpr associated with the call and checking if the given
00378 /// symbol is returned or is one of the arguments.
00379 /// The hint can be customized by redefining 'getMessageForX()' methods.
00380 class StackHintGeneratorForSymbol : public StackHintGenerator {
00381 private:
00382   SymbolRef Sym;
00383   std::string Msg;
00384 
00385 public:
00386   StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
00387   virtual ~StackHintGeneratorForSymbol() {}
00388 
00389   /// \brief Search the call expression for the symbol Sym and dispatch the
00390   /// 'getMessageForX()' methods to construct a specific message.
00391   virtual std::string getMessage(const ExplodedNode *N);
00392 
00393   /// Prints the ordinal form of the given integer,
00394   /// only valid for ValNo : ValNo > 0.
00395   void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out);
00396 
00397   /// Produces the message of the following form:
00398   ///   'Msg via Nth parameter'
00399   virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
00400   virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
00401     return Msg;
00402   }
00403   virtual std::string getMessageForSymbolNotFound() {
00404     return Msg;
00405   }
00406 };
00407 
00408 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
00409   llvm::Optional<bool> IsPrunable;
00410 
00411   /// If the event occurs in a different frame than the final diagnostic,
00412   /// supply a message that will be used to construct an extra hint on the
00413   /// returns from all the calls on the stack from this event to the final
00414   /// diagnostic.
00415   llvm::OwningPtr<StackHintGenerator> CallStackHint;
00416 
00417 public:
00418   PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
00419                            StringRef s, bool addPosRange = true,
00420                            StackHintGenerator *stackHint = 0)
00421     : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
00422       CallStackHint(stackHint) {}
00423 
00424   ~PathDiagnosticEventPiece();
00425 
00426   /// Mark the diagnostic piece as being potentially prunable.  This
00427   /// flag may have been previously set, at which point it will not
00428   /// be reset unless one specifies to do so.
00429   void setPrunable(bool isPrunable, bool override = false) {
00430     if (IsPrunable.hasValue() && !override)
00431      return;
00432     IsPrunable = isPrunable;
00433   }
00434 
00435   /// Return true if the diagnostic piece is prunable.
00436   bool isPrunable() const {
00437     return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
00438   }
00439   
00440   bool hasCallStackHint() {
00441     return (CallStackHint != 0);
00442   }
00443 
00444   /// Produce the hint for the given node. The node contains 
00445   /// information about the call for which the diagnostic can be generated.
00446   std::string getCallStackMessage(const ExplodedNode *N) {
00447     if (CallStackHint)
00448       return CallStackHint->getMessage(N);
00449     return "";  
00450   }
00451 
00452   static inline bool classof(const PathDiagnosticPiece *P) {
00453     return P->getKind() == Event;
00454   }
00455 };
00456 
00457 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
00458   PathDiagnosticCallPiece(const Decl *callerD,
00459                           const PathDiagnosticLocation &callReturnPos)
00460     : PathDiagnosticPiece(Call), Caller(callerD), Callee(0),
00461       NoExit(false), callReturn(callReturnPos) {}
00462 
00463   PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
00464     : PathDiagnosticPiece(Call), Caller(caller), Callee(0),
00465       NoExit(true), path(oldPath) {}
00466   
00467   const Decl *Caller;
00468   const Decl *Callee;
00469 
00470   // Flag signifying that this diagnostic has only call enter and no matching
00471   // call exit.
00472   bool NoExit;
00473 
00474   // The custom string, which should appear after the call Return Diagnostic.
00475   // TODO: Should we allow multiple diagnostics?
00476   std::string CallStackMessage;
00477 
00478 public:
00479   PathDiagnosticLocation callEnter;
00480   PathDiagnosticLocation callEnterWithin;
00481   PathDiagnosticLocation callReturn;  
00482   PathPieces path;
00483   
00484   virtual ~PathDiagnosticCallPiece();
00485   
00486   const Decl *getCaller() const { return Caller; }
00487   
00488   const Decl *getCallee() const { return Callee; }
00489   void setCallee(const CallEnter &CE, const SourceManager &SM);
00490   
00491   bool hasCallStackMessage() { return !CallStackMessage.empty(); }
00492   void setCallStackMessage(StringRef st) {
00493     CallStackMessage = st;
00494   }
00495 
00496   virtual PathDiagnosticLocation getLocation() const {
00497     return callEnter;
00498   }
00499   
00500   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const;
00501   IntrusiveRefCntPtr<PathDiagnosticEventPiece>
00502     getCallEnterWithinCallerEvent() const;
00503   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const;
00504 
00505   virtual void flattenLocations() {
00506     callEnter.flatten();
00507     callReturn.flatten();
00508     for (PathPieces::iterator I = path.begin(), 
00509          E = path.end(); I != E; ++I) (*I)->flattenLocations();
00510   }
00511   
00512   static PathDiagnosticCallPiece *construct(const ExplodedNode *N,
00513                                             const CallExitEnd &CE,
00514                                             const SourceManager &SM);
00515   
00516   static PathDiagnosticCallPiece *construct(PathPieces &pieces,
00517                                             const Decl *caller);
00518   
00519   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
00520 
00521   static inline bool classof(const PathDiagnosticPiece *P) {
00522     return P->getKind() == Call;
00523   }
00524 };
00525 
00526 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
00527   std::vector<PathDiagnosticLocationPair> LPairs;
00528 public:
00529   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
00530                                  const PathDiagnosticLocation &endPos,
00531                                  StringRef s)
00532     : PathDiagnosticPiece(s, ControlFlow) {
00533       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
00534     }
00535 
00536   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
00537                                  const PathDiagnosticLocation &endPos)
00538     : PathDiagnosticPiece(ControlFlow) {
00539       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
00540     }
00541 
00542   ~PathDiagnosticControlFlowPiece();
00543 
00544   PathDiagnosticLocation getStartLocation() const {
00545     assert(!LPairs.empty() &&
00546            "PathDiagnosticControlFlowPiece needs at least one location.");
00547     return LPairs[0].getStart();
00548   }
00549 
00550   PathDiagnosticLocation getEndLocation() const {
00551     assert(!LPairs.empty() &&
00552            "PathDiagnosticControlFlowPiece needs at least one location.");
00553     return LPairs[0].getEnd();
00554   }
00555 
00556   void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
00557 
00558   virtual PathDiagnosticLocation getLocation() const {
00559     return getStartLocation();
00560   }
00561 
00562   typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
00563   iterator begin() { return LPairs.begin(); }
00564   iterator end()   { return LPairs.end(); }
00565 
00566   virtual void flattenLocations() {
00567     for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
00568   }
00569 
00570   typedef std::vector<PathDiagnosticLocationPair>::const_iterator
00571           const_iterator;
00572   const_iterator begin() const { return LPairs.begin(); }
00573   const_iterator end() const   { return LPairs.end(); }
00574 
00575   static inline bool classof(const PathDiagnosticPiece *P) {
00576     return P->getKind() == ControlFlow;
00577   }
00578   
00579   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
00580 };
00581 
00582 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
00583 public:
00584   PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
00585     : PathDiagnosticSpotPiece(pos, "", Macro) {}
00586 
00587   ~PathDiagnosticMacroPiece();
00588 
00589   PathPieces subPieces;
00590   
00591   bool containsEvent() const;
00592 
00593   virtual void flattenLocations() {
00594     PathDiagnosticSpotPiece::flattenLocations();
00595     for (PathPieces::iterator I = subPieces.begin(), 
00596          E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
00597   }
00598 
00599   static inline bool classof(const PathDiagnosticPiece *P) {
00600     return P->getKind() == Macro;
00601   }
00602   
00603   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
00604 };
00605 
00606 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
00607 ///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
00608 ///  each which represent the pieces of the path.
00609 class PathDiagnostic : public llvm::FoldingSetNode {
00610   const Decl *DeclWithIssue;
00611   std::string BugType;
00612   std::string Desc;
00613   std::string Category;
00614   std::deque<std::string> OtherDesc;
00615   PathPieces pathImpl;
00616   llvm::SmallVector<PathPieces *, 3> pathStack;
00617   
00618   PathDiagnostic(); // Do not implement.
00619 public:
00620   const PathPieces &path;
00621 
00622   /// Return the path currently used by builders for constructing the 
00623   /// PathDiagnostic.
00624   PathPieces &getActivePath() {
00625     if (pathStack.empty())
00626       return pathImpl;
00627     return *pathStack.back();
00628   }
00629   
00630   /// Return a mutable version of 'path'.
00631   PathPieces &getMutablePieces() {
00632     return pathImpl;
00633   }
00634     
00635   /// Return the unrolled size of the path.
00636   unsigned full_size();
00637 
00638   void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
00639   void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
00640   
00641   //  PathDiagnostic();
00642   PathDiagnostic(const Decl *DeclWithIssue,
00643                  StringRef bugtype,
00644                  StringRef desc,
00645                  StringRef category);
00646 
00647   ~PathDiagnostic();
00648 
00649   StringRef getDescription() const { return Desc; }
00650   StringRef getBugType() const { return BugType; }
00651   StringRef getCategory() const { return Category; }
00652 
00653   /// Return the semantic context where an issue occurred.  If the
00654   /// issue occurs along a path, this represents the "central" area
00655   /// where the bug manifests.
00656   const Decl *getDeclWithIssue() const { return DeclWithIssue; }
00657 
00658   typedef std::deque<std::string>::const_iterator meta_iterator;
00659   meta_iterator meta_begin() const { return OtherDesc.begin(); }
00660   meta_iterator meta_end() const { return OtherDesc.end(); }
00661   void addMeta(StringRef s) { OtherDesc.push_back(s); }
00662 
00663   PathDiagnosticLocation getLocation() const;
00664 
00665   void flattenLocations() {
00666     for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); 
00667          I != E; ++I) (*I)->flattenLocations();
00668   }
00669   
00670   void Profile(llvm::FoldingSetNodeID &ID) const;
00671   
00672   void FullProfile(llvm::FoldingSetNodeID &ID) const;
00673 };  
00674 
00675 } // end GR namespace
00676 
00677 } //end clang namespace
00678 
00679 #endif