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