]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/clang/include/clang/Analysis/PathDiagnostic.h
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / clang / include / clang / Analysis / PathDiagnostic.h
1 //===- PathDiagnostic.h - Path-Specific Diagnostic Handling -----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines the PathDiagnostic-related interfaces.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
14 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
15
16 #include "clang/AST/Stmt.h"
17 #include "clang/Analysis/AnalysisDeclContext.h"
18 #include "clang/Basic/LLVM.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include "llvm/ADT/ArrayRef.h"
21 #include "llvm/ADT/FoldingSet.h"
22 #include "llvm/ADT/Optional.h"
23 #include "llvm/ADT/PointerUnion.h"
24 #include "llvm/ADT/SmallVector.h"
25 #include "llvm/ADT/StringRef.h"
26 #include "llvm/Support/Allocator.h"
27 #include <cassert>
28 #include <deque>
29 #include <iterator>
30 #include <list>
31 #include <map>
32 #include <memory>
33 #include <set>
34 #include <string>
35 #include <utility>
36 #include <vector>
37
38 namespace clang {
39
40 class AnalysisDeclContext;
41 class BinaryOperator;
42 class CallEnter;
43 class CallExitEnd;
44 class CallExpr;
45 class ConditionalOperator;
46 class Decl;
47 class Expr;
48 class LocationContext;
49 class MemberExpr;
50 class ProgramPoint;
51 class SourceManager;
52
53 namespace ento {
54
55 //===----------------------------------------------------------------------===//
56 // High-level interface for handlers of path-sensitive diagnostics.
57 //===----------------------------------------------------------------------===//
58
59 class PathDiagnostic;
60
61 class PathDiagnosticConsumer {
62 public:
63   class PDFileEntry : public llvm::FoldingSetNode {
64   public:
65     PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
66
67     using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
68
69     /// A vector of <consumer,file> pairs.
70     ConsumerFiles files;
71
72     /// A precomputed hash tag used for uniquing PDFileEntry objects.
73     const llvm::FoldingSetNodeID NodeID;
74
75     /// Used for profiling in the FoldingSet.
76     void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
77   };
78
79   class FilesMade {
80     llvm::BumpPtrAllocator Alloc;
81     llvm::FoldingSet<PDFileEntry> Set;
82
83   public:
84     ~FilesMade();
85
86     bool empty() const { return Set.empty(); }
87
88     void addDiagnostic(const PathDiagnostic &PD,
89                        StringRef ConsumerName,
90                        StringRef fileName);
91
92     PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
93   };
94
95 private:
96   virtual void anchor();
97
98 public:
99   PathDiagnosticConsumer() = default;
100   virtual ~PathDiagnosticConsumer();
101
102   void FlushDiagnostics(FilesMade *FilesMade);
103
104   virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
105                                     FilesMade *filesMade) = 0;
106
107   virtual StringRef getName() const = 0;
108
109   void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
110
111   enum PathGenerationScheme {
112     /// Only runs visitors, no output generated.
113     None,
114
115     /// Used for HTML, SARIF, and text output.
116     Minimal,
117
118     /// Used for plist output, used for "arrows" generation.
119     Extensive,
120   };
121
122   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
123
124   bool shouldGenerateDiagnostics() const {
125     return getGenerationScheme() != None;
126   }
127
128   bool shouldAddPathEdges() const { return getGenerationScheme() == Extensive; }
129
130   virtual bool supportsLogicalOpControlFlow() const { return false; }
131
132   /// Return true if the PathDiagnosticConsumer supports individual
133   /// PathDiagnostics that span multiple files.
134   virtual bool supportsCrossFileDiagnostics() const { return false; }
135
136 protected:
137   bool flushed = false;
138   llvm::FoldingSet<PathDiagnostic> Diags;
139 };
140
141 //===----------------------------------------------------------------------===//
142 // Path-sensitive diagnostics.
143 //===----------------------------------------------------------------------===//
144
145 class PathDiagnosticRange : public SourceRange {
146 public:
147   bool isPoint = false;
148
149   PathDiagnosticRange(SourceRange R, bool isP = false)
150       : SourceRange(R), isPoint(isP) {}
151   PathDiagnosticRange() = default;
152 };
153
154 using LocationOrAnalysisDeclContext =
155     llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
156
157 class PathDiagnosticLocation {
158 private:
159   enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
160
161   const Stmt *S = nullptr;
162   const Decl *D = nullptr;
163   const SourceManager *SM = nullptr;
164   FullSourceLoc Loc;
165   PathDiagnosticRange Range;
166
167   PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
168       : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
169
170   FullSourceLoc genLocation(
171       SourceLocation L = SourceLocation(),
172       LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
173
174   PathDiagnosticRange genRange(
175       LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
176
177 public:
178   /// Create an invalid location.
179   PathDiagnosticLocation() = default;
180
181   /// Create a location corresponding to the given statement.
182   PathDiagnosticLocation(const Stmt *s, const SourceManager &sm,
183                          LocationOrAnalysisDeclContext lac)
184       : K(s->getBeginLoc().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 ProgramPoint.
275   static PathDiagnosticLocation create(const ProgramPoint &P,
276                                        const SourceManager &SMng);
277
278   /// Convert the given location into a single kind location.
279   static PathDiagnosticLocation createSingleLocation(
280                                              const PathDiagnosticLocation &PDL);
281
282   /// Construct a source location that corresponds to either the beginning
283   /// or the end of the given statement, or a nearby valid source location
284   /// if the statement does not have a valid source location of its own.
285   static SourceLocation
286   getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC,
287                          bool UseEndOfStatement = false);
288
289   bool operator==(const PathDiagnosticLocation &X) const {
290     return K == X.K && Loc == X.Loc && Range == X.Range;
291   }
292
293   bool operator!=(const PathDiagnosticLocation &X) const {
294     return !(*this == X);
295   }
296
297   bool isValid() const {
298     return SM != nullptr;
299   }
300
301   FullSourceLoc asLocation() const {
302     return Loc;
303   }
304
305   PathDiagnosticRange asRange() const {
306     return Range;
307   }
308
309   const Stmt *asStmt() const { assert(isValid()); return S; }
310   const Stmt *getStmtOrNull() const {
311     if (!isValid())
312       return nullptr;
313     return asStmt();
314   }
315
316   const Decl *asDecl() const { assert(isValid()); return D; }
317
318   bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
319
320   bool hasValidLocation() const { return asLocation().isValid(); }
321
322   void invalidate() {
323     *this = PathDiagnosticLocation();
324   }
325
326   void flatten();
327
328   const SourceManager& getManager() const { assert(isValid()); return *SM; }
329
330   void Profile(llvm::FoldingSetNodeID &ID) const;
331
332   void dump() const;
333 };
334
335 class PathDiagnosticLocationPair {
336 private:
337   PathDiagnosticLocation Start, End;
338
339 public:
340   PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
341                              const PathDiagnosticLocation &end)
342       : Start(start), End(end) {}
343
344   const PathDiagnosticLocation &getStart() const { return Start; }
345   const PathDiagnosticLocation &getEnd() const { return End; }
346
347   void setStart(const PathDiagnosticLocation &L) { Start = L; }
348   void setEnd(const PathDiagnosticLocation &L) { End = L; }
349
350   void flatten() {
351     Start.flatten();
352     End.flatten();
353   }
354
355   void Profile(llvm::FoldingSetNodeID &ID) const {
356     Start.Profile(ID);
357     End.Profile(ID);
358   }
359 };
360
361 //===----------------------------------------------------------------------===//
362 // Path "pieces" for path-sensitive diagnostics.
363 //===----------------------------------------------------------------------===//
364
365 class PathDiagnosticPiece: public llvm::FoldingSetNode {
366 public:
367   enum Kind { ControlFlow, Event, Macro, Call, Note, PopUp };
368   enum DisplayHint { Above, Below };
369
370 private:
371   const std::string str;
372   const Kind kind;
373   const DisplayHint Hint;
374
375   /// In the containing bug report, this piece is the last piece from
376   /// the main source file.
377   bool LastInMainSourceFile = false;
378
379   /// A constant string that can be used to tag the PathDiagnosticPiece,
380   /// typically with the identification of the creator.  The actual pointer
381   /// value is meant to be an identifier; the string itself is useful for
382   /// debugging.
383   StringRef Tag;
384
385   std::vector<SourceRange> ranges;
386   std::vector<FixItHint> fixits;
387
388 protected:
389   PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
390   PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
391
392 public:
393   PathDiagnosticPiece() = delete;
394   PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
395   PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
396   virtual ~PathDiagnosticPiece();
397
398   StringRef getString() const { return str; }
399
400   /// Tag this PathDiagnosticPiece with the given C-string.
401   void setTag(const char *tag) { Tag = tag; }
402
403   /// Return the opaque tag (if any) on the PathDiagnosticPiece.
404   const void *getTag() const { return Tag.data(); }
405
406   /// Return the string representation of the tag.  This is useful
407   /// for debugging.
408   StringRef getTagStr() const { return Tag; }
409
410   /// getDisplayHint - Return a hint indicating where the diagnostic should
411   ///  be displayed by the PathDiagnosticConsumer.
412   DisplayHint getDisplayHint() const { return Hint; }
413
414   virtual PathDiagnosticLocation getLocation() const = 0;
415   virtual void flattenLocations() = 0;
416
417   Kind getKind() const { return kind; }
418
419   void addRange(SourceRange R) {
420     if (!R.isValid())
421       return;
422     ranges.push_back(R);
423   }
424
425   void addRange(SourceLocation B, SourceLocation E) {
426     if (!B.isValid() || !E.isValid())
427       return;
428     ranges.push_back(SourceRange(B,E));
429   }
430
431   void addFixit(FixItHint F) {
432     fixits.push_back(F);
433   }
434
435   /// Return the SourceRanges associated with this PathDiagnosticPiece.
436   ArrayRef<SourceRange> getRanges() const { return ranges; }
437
438   /// Return the fix-it hints associated with this PathDiagnosticPiece.
439   ArrayRef<FixItHint> getFixits() const { return fixits; }
440
441   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
442
443   void setAsLastInMainSourceFile() {
444     LastInMainSourceFile = true;
445   }
446
447   bool isLastInMainSourceFile() const {
448     return LastInMainSourceFile;
449   }
450
451   virtual void dump() const = 0;
452 };
453
454 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
455
456 class PathPieces : public std::list<PathDiagnosticPieceRef> {
457   void flattenTo(PathPieces &Primary, PathPieces &Current,
458                  bool ShouldFlattenMacros) const;
459
460 public:
461   PathPieces flatten(bool ShouldFlattenMacros) const {
462     PathPieces Result;
463     flattenTo(Result, Result, ShouldFlattenMacros);
464     return Result;
465   }
466
467   void dump() const;
468 };
469
470 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
471 private:
472   PathDiagnosticLocation Pos;
473
474 public:
475   PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
476                           StringRef s,
477                           PathDiagnosticPiece::Kind k,
478                           bool addPosRange = true)
479       : PathDiagnosticPiece(s, k), Pos(pos) {
480     assert(Pos.isValid() && Pos.hasValidLocation() &&
481            "PathDiagnosticSpotPiece's must have a valid location.");
482     if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
483   }
484
485   PathDiagnosticLocation getLocation() const override { return Pos; }
486   void flattenLocations() override { Pos.flatten(); }
487
488   void Profile(llvm::FoldingSetNodeID &ID) const override;
489
490   static bool classof(const PathDiagnosticPiece *P) {
491     return P->getKind() == Event || P->getKind() == Macro ||
492            P->getKind() == Note || P->getKind() == PopUp;
493   }
494 };
495
496 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
497   Optional<bool> IsPrunable;
498
499 public:
500   PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
501                            StringRef s, bool addPosRange = true)
502       : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
503   ~PathDiagnosticEventPiece() override;
504
505   /// Mark the diagnostic piece as being potentially prunable.  This
506   /// flag may have been previously set, at which point it will not
507   /// be reset unless one specifies to do so.
508   void setPrunable(bool isPrunable, bool override = false) {
509     if (IsPrunable.hasValue() && !override)
510      return;
511     IsPrunable = isPrunable;
512   }
513
514   /// Return true if the diagnostic piece is prunable.
515   bool isPrunable() const {
516     return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
517   }
518
519   void dump() const override;
520
521   static bool classof(const PathDiagnosticPiece *P) {
522     return P->getKind() == Event;
523   }
524 };
525
526 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
527   const Decl *Caller;
528   const Decl *Callee = nullptr;
529
530   // Flag signifying that this diagnostic has only call enter and no matching
531   // call exit.
532   bool NoExit;
533
534   // Flag signifying that the callee function is an Objective-C autosynthesized
535   // property getter or setter.
536   bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
537
538   // The custom string, which should appear after the call Return Diagnostic.
539   // TODO: Should we allow multiple diagnostics?
540   std::string CallStackMessage;
541
542   PathDiagnosticCallPiece(const Decl *callerD,
543                           const PathDiagnosticLocation &callReturnPos)
544       : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
545         callReturn(callReturnPos) {}
546   PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
547       : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
548         path(oldPath) {}
549
550 public:
551   PathDiagnosticLocation callEnter;
552   PathDiagnosticLocation callEnterWithin;
553   PathDiagnosticLocation callReturn;
554   PathPieces path;
555
556   ~PathDiagnosticCallPiece() override;
557
558   const Decl *getCaller() const { return Caller; }
559
560   const Decl *getCallee() const { return Callee; }
561   void setCallee(const CallEnter &CE, const SourceManager &SM);
562
563   bool hasCallStackMessage() { return !CallStackMessage.empty(); }
564   void setCallStackMessage(StringRef st) { CallStackMessage = st; }
565
566   PathDiagnosticLocation getLocation() const override { return callEnter; }
567
568   std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
569   std::shared_ptr<PathDiagnosticEventPiece>
570   getCallEnterWithinCallerEvent() const;
571   std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
572
573   void flattenLocations() override {
574     callEnter.flatten();
575     callReturn.flatten();
576     for (const auto &I : path)
577       I->flattenLocations();
578   }
579
580   static std::shared_ptr<PathDiagnosticCallPiece>
581   construct(const CallExitEnd &CE,
582             const SourceManager &SM);
583
584   static PathDiagnosticCallPiece *construct(PathPieces &pieces,
585                                             const Decl *caller);
586
587   void dump() const override;
588
589   void Profile(llvm::FoldingSetNodeID &ID) const override;
590
591   static bool classof(const PathDiagnosticPiece *P) {
592     return P->getKind() == Call;
593   }
594 };
595
596 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
597   std::vector<PathDiagnosticLocationPair> LPairs;
598
599 public:
600   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
601                                  const PathDiagnosticLocation &endPos,
602                                  StringRef s)
603       : PathDiagnosticPiece(s, ControlFlow) {
604     LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
605   }
606
607   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
608                                  const PathDiagnosticLocation &endPos)
609       : PathDiagnosticPiece(ControlFlow) {
610     LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
611   }
612
613   ~PathDiagnosticControlFlowPiece() override;
614
615   PathDiagnosticLocation getStartLocation() const {
616     assert(!LPairs.empty() &&
617            "PathDiagnosticControlFlowPiece needs at least one location.");
618     return LPairs[0].getStart();
619   }
620
621   PathDiagnosticLocation getEndLocation() const {
622     assert(!LPairs.empty() &&
623            "PathDiagnosticControlFlowPiece needs at least one location.");
624     return LPairs[0].getEnd();
625   }
626
627   void setStartLocation(const PathDiagnosticLocation &L) {
628     LPairs[0].setStart(L);
629   }
630
631   void setEndLocation(const PathDiagnosticLocation &L) {
632     LPairs[0].setEnd(L);
633   }
634
635   void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
636
637   PathDiagnosticLocation getLocation() const override {
638     return getStartLocation();
639   }
640
641   using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
642
643   iterator begin() { return LPairs.begin(); }
644   iterator end() { return LPairs.end(); }
645
646   void flattenLocations() override {
647     for (auto &I : *this)
648       I.flatten();
649   }
650
651   using const_iterator =
652       std::vector<PathDiagnosticLocationPair>::const_iterator;
653
654   const_iterator begin() const { return LPairs.begin(); }
655   const_iterator end() const { return LPairs.end(); }
656
657   static bool classof(const PathDiagnosticPiece *P) {
658     return P->getKind() == ControlFlow;
659   }
660
661   void dump() const override;
662
663   void Profile(llvm::FoldingSetNodeID &ID) const override;
664 };
665
666 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
667 public:
668   PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
669       : PathDiagnosticSpotPiece(pos, "", Macro) {}
670   ~PathDiagnosticMacroPiece() override;
671
672   PathPieces subPieces;
673
674   void flattenLocations() override {
675     PathDiagnosticSpotPiece::flattenLocations();
676     for (const auto &I : subPieces)
677       I->flattenLocations();
678   }
679
680   static bool classof(const PathDiagnosticPiece *P) {
681     return P->getKind() == Macro;
682   }
683
684   void dump() const override;
685
686   void Profile(llvm::FoldingSetNodeID &ID) const override;
687 };
688
689 class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
690 public:
691   PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
692                           bool AddPosRange = true)
693       : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
694   ~PathDiagnosticNotePiece() override;
695
696   static bool classof(const PathDiagnosticPiece *P) {
697     return P->getKind() == Note;
698   }
699
700   void dump() const override;
701
702   void Profile(llvm::FoldingSetNodeID &ID) const override;
703 };
704
705 class PathDiagnosticPopUpPiece: public PathDiagnosticSpotPiece {
706 public:
707   PathDiagnosticPopUpPiece(const PathDiagnosticLocation &Pos, StringRef S,
708                            bool AddPosRange = true)
709       : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
710   ~PathDiagnosticPopUpPiece() override;
711
712   static bool classof(const PathDiagnosticPiece *P) {
713     return P->getKind() == PopUp;
714   }
715
716   void dump() const override;
717
718   void Profile(llvm::FoldingSetNodeID &ID) const override;
719 };
720
721 /// File IDs mapped to sets of line numbers.
722 using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
723
724 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
725 ///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
726 ///  each which represent the pieces of the path.
727 class PathDiagnostic : public llvm::FoldingSetNode {
728   std::string CheckerName;
729   const Decl *DeclWithIssue;
730   std::string BugType;
731   std::string VerboseDesc;
732   std::string ShortDesc;
733   std::string Category;
734   std::deque<std::string> OtherDesc;
735
736   /// Loc The location of the path diagnostic report.
737   PathDiagnosticLocation Loc;
738
739   PathPieces pathImpl;
740   SmallVector<PathPieces *, 3> pathStack;
741
742   /// Important bug uniqueing location.
743   /// The location info is useful to differentiate between bugs.
744   PathDiagnosticLocation UniqueingLoc;
745   const Decl *UniqueingDecl;
746
747   /// Lines executed in the path.
748   std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
749
750 public:
751   PathDiagnostic() = delete;
752   PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
753                  StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
754                  StringRef category, PathDiagnosticLocation LocationToUnique,
755                  const Decl *DeclToUnique,
756                  std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
757   ~PathDiagnostic();
758
759   const PathPieces &path;
760
761   /// Return the path currently used by builders for constructing the
762   /// PathDiagnostic.
763   PathPieces &getActivePath() {
764     if (pathStack.empty())
765       return pathImpl;
766     return *pathStack.back();
767   }
768
769   /// Return a mutable version of 'path'.
770   PathPieces &getMutablePieces() {
771     return pathImpl;
772   }
773
774   /// Return the unrolled size of the path.
775   unsigned full_size();
776
777   void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
778   void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
779
780   bool isWithinCall() const { return !pathStack.empty(); }
781
782   void setEndOfPath(PathDiagnosticPieceRef EndPiece) {
783     assert(!Loc.isValid() && "End location already set!");
784     Loc = EndPiece->getLocation();
785     assert(Loc.isValid() && "Invalid location for end-of-path piece");
786     getActivePath().push_back(std::move(EndPiece));
787   }
788
789   void appendToDesc(StringRef S) {
790     if (!ShortDesc.empty())
791       ShortDesc += S;
792     VerboseDesc += S;
793   }
794
795   StringRef getVerboseDescription() const { return VerboseDesc; }
796
797   StringRef getShortDescription() const {
798     return ShortDesc.empty() ? VerboseDesc : ShortDesc;
799   }
800
801   StringRef getCheckerName() const { return CheckerName; }
802   StringRef getBugType() const { return BugType; }
803   StringRef getCategory() const { return Category; }
804
805   using meta_iterator = std::deque<std::string>::const_iterator;
806
807   meta_iterator meta_begin() const { return OtherDesc.begin(); }
808   meta_iterator meta_end() const { return OtherDesc.end(); }
809   void addMeta(StringRef s) { OtherDesc.push_back(s); }
810
811   const FilesToLineNumsMap &getExecutedLines() const {
812     return *ExecutedLines;
813   }
814
815   FilesToLineNumsMap &getExecutedLines() {
816     return *ExecutedLines;
817   }
818
819   /// Return the semantic context where an issue occurred.  If the
820   /// issue occurs along a path, this represents the "central" area
821   /// where the bug manifests.
822   const Decl *getDeclWithIssue() const { return DeclWithIssue; }
823
824   void setDeclWithIssue(const Decl *D) {
825     DeclWithIssue = D;
826   }
827
828   PathDiagnosticLocation getLocation() const {
829     return Loc;
830   }
831
832   void setLocation(PathDiagnosticLocation NewLoc) {
833     Loc = NewLoc;
834   }
835
836   /// Get the location on which the report should be uniqued.
837   PathDiagnosticLocation getUniqueingLoc() const {
838     return UniqueingLoc;
839   }
840
841   /// Get the declaration containing the uniqueing location.
842   const Decl *getUniqueingDecl() const {
843     return UniqueingDecl;
844   }
845
846   void flattenLocations() {
847     Loc.flatten();
848     for (const auto &I : pathImpl)
849       I->flattenLocations();
850   }
851
852   /// Profiles the diagnostic, independent of the path it references.
853   ///
854   /// This can be used to merge diagnostics that refer to the same issue
855   /// along different paths.
856   void Profile(llvm::FoldingSetNodeID &ID) const;
857
858   /// Profiles the diagnostic, including its path.
859   ///
860   /// Two diagnostics with the same issue along different paths will generate
861   /// different profiles.
862   void FullProfile(llvm::FoldingSetNodeID &ID) const;
863 };
864
865 } // namespace ento
866 } // namespace clang
867
868 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H