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