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