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