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