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