clang  8.0.0svn
PathDiagnostic.h
Go to the documentation of this file.
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"
19 #include "clang/Basic/LLVM.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 
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.
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 
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 
118  /// Only runs visitors, no output generated.
120 
121  /// Used for HTML and text output.
123 
124  /// Used for plist output, used for "arrows" generation.
126  };
127 
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 
145 public:
146  bool isPoint = false;
147 
148  PathDiagnosticRange(SourceRange R, bool isP = false)
149  : SourceRange(R), isPoint(isP) {}
150  PathDiagnosticRange() = default;
151 };
152 
154  llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
155 
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;
165 
167  : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
168 
169  FullSourceLoc genLocation(
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.
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.
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.
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.
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.
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,
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,
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.
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 
299  return Loc;
300  }
301 
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 
338 private:
340 
341 public:
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 
421  if (!R.isValid())
422  return;
423  ranges.push_back(R);
424  }
425 
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 
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 
463 private:
465 
466 public:
468  StringRef s,
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.
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.
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 
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:
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 
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:
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 
651  std::vector<PathDiagnosticLocationPair> LPairs;
652 
653 public:
655  const PathDiagnosticLocation &endPos,
656  StringRef s)
657  : PathDiagnosticPiece(s, ControlFlow) {
658  LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
659  }
660 
662  const PathDiagnosticLocation &endPos)
663  : PathDiagnosticPiece(ControlFlow) {
664  LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
665  }
666 
667  ~PathDiagnosticControlFlowPiece() override;
668 
670  assert(!LPairs.empty() &&
671  "PathDiagnosticControlFlowPiece needs at least one location.");
672  return LPairs[0].getStart();
673  }
674 
676  assert(!LPairs.empty() &&
677  "PathDiagnosticControlFlowPiece needs at least one location.");
678  return LPairs[0].getEnd();
679  }
680 
682  LPairs[0].setStart(L);
683  }
684 
686  LPairs[0].setEnd(L);
687  }
688 
689  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
690 
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 
721 public:
723  : PathDiagnosticSpotPiece(pos, "", Macro) {}
724  ~PathDiagnosticMacroPiece() override;
725 
727 
728  bool containsEvent() const;
729 
730  void flattenLocations() override {
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 
746 public:
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.
778 
779  PathPieces pathImpl;
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.
804  if (pathStack.empty())
805  return pathImpl;
806  return *pathStack.back();
807  }
808 
809  /// Return a mutable version of 'path'.
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 
862  return *ExecutedLines;
863  }
864 
866  return *ExecutedLines;
867  }
868 
870  return Loc;
871  }
872 
873  /// Get the location on which the report should be uniqued.
875  return UniqueingLoc;
876  }
877 
878  /// Get the declaration containing the uniqueing location.
879  const Decl *getUniqueingDecl() const {
880  return UniqueingDecl;
881  }
882 
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
PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, StringRef s, PathDiagnosticPiece::Kind k, bool addPosRange=true)
virtual void FlushDiagnosticsImpl(std::vector< const PathDiagnostic *> &Diags, FilesMade *filesMade)=0
void setTag(const char *tag)
Tag this PathDiagnosticPiece with the given C-string.
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, const PathDiagnosticLocation &endPos, StringRef s)
PathDiagnosticLocation getLocation() const override
Stmt - This represents one statement.
Definition: Stmt.h:66
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:87
virtual StringRef getName() const =0
Represents a point when we begin processing an inlined call.
Definition: ProgramPoint.h:632
StringRef P
Constructs a Stack hint for the given symbol.
void Profile(llvm::FoldingSetNodeID &ID) const
A Range represents the closed range [from, to].
PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
void setPrunable(bool isPrunable, bool override=false)
Mark the diagnostic piece as being potentially prunable.
PathDiagnosticLocation getStartLocation() const
const PathDiagnosticLocation & getEnd() const
bool operator==(const PathDiagnosticLocation &X) const
meta_iterator meta_begin() const
const FilesToLineNumsMap & getExecutedLines() const
PathDiagnosticLocation getLocation() const
Symbolic value.
Definition: SymExpr.h:30
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S, bool AddPosRange=true)
void setStartLocation(const PathDiagnosticLocation &L)
void addRange(SourceLocation B, SourceLocation E)
AnalysisDeclContext contains the context data for the function or method under analysis.
static bool classof(const PathDiagnosticPiece *P)
StringRef getVerboseDescription() const
void pushActivePath(PathPieces *p)
int Category
Definition: Format.cpp:1623
FilesToLineNumsMap & getExecutedLines()
virtual bool supportsLogicalOpControlFlow() const
PathPieces & getMutablePieces()
Return a mutable version of &#39;path&#39;.
PDFileEntry(llvm::FoldingSetNodeID &NodeID)
llvm::FoldingSet< PathDiagnostic > Diags
void setStart(const PathDiagnosticLocation &L)
virtual std::string getMessageForReturn(const CallExpr *CallExpr)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
std::vector< std::pair< StringRef, StringRef > > ConsumerFiles
bool operator!=(const PathDiagnosticLocation &X) const
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3107
StringRef getBugType() const
void setEndOfPath(std::shared_ptr< PathDiagnosticPiece > EndPiece)
meta_iterator meta_end() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
StringRef getCheckName() const
PathDiagnosticLocation(const Stmt *s, const SourceManager &sm, LocationOrAnalysisDeclContext lac)
Create a location corresponding to the given statement.
PathDiagnosticLocation getEndLocation() const
ConditionalOperator - The ?: ternary operator.
Definition: Expr.h:3397
return Out str()
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:613
const void * getTag() const
Return the opaque tag (if any) on the PathDiagnosticPiece.
void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)
std::vector< PathDiagnosticLocationPair >::const_iterator const_iterator
Represents a point when we finish the call exit sequence (for inlined call).
Definition: ProgramPoint.h:690
DisplayHint getDisplayHint() const
getDisplayHint - Return a hint indicating where the diagnostic should be displayed by the PathDiagnos...
This represents one expression.
Definition: Expr.h:105
bool isPrunable() const
Return true if the diagnostic piece is prunable.
SourceLocation End
PathDiagnosticLocation getUniqueingLoc() const
Get the location on which the report should be uniqued.
std::vector< PathDiagnosticLocationPair >::iterator iterator
const SourceManager & getManager() const
llvm::PointerUnion< const LocationContext *, AnalysisDeclContext * > LocationOrAnalysisDeclContext
PathDiagnosticRange(SourceRange R, bool isP=false)
virtual std::string getMessageForSymbolNotFound()
Interface for classes constructing Stack hints.
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
PathPieces flatten(bool ShouldFlattenMacros) const
const SourceManager & SM
Definition: Format.cpp:1490
StringRef getCategory() const
Only runs visitors, no output generated.
const llvm::FoldingSetNodeID NodeID
A precomputed hash tag used for uniquing PDFileEntry objects.
void Profile(llvm::FoldingSetNodeID &ID) const
Encodes a location in the source.
std::string getCallStackMessage(const ExplodedNode *N)
Produce the hint for the given node.
std::deque< std::string >::const_iterator meta_iterator
virtual bool supportsCrossFileDiagnostics() const
Return true if the PathDiagnosticConsumer supports individual PathDiagnostics that span multiple file...
PathDiagnosticLocation getLocation() const override
Used for plist output, used for "arrows" generation.
ConsumerFiles files
A vector of <consumer,file> pairs.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the beginning of the declaration.
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
Dataflow Directional Tag Classes.
const PathDiagnosticLocation & getStart() const
bool isValid() const
Return true if this is a valid SourceLocation object.
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, const PathDiagnosticLocation &endPos)
void FlushDiagnostics(FilesMade *FilesMade)
PathDiagnosticRange asRange() const
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, StringRef s, bool addPosRange=true, StackHintGenerator *stackHint=nullptr)
void setEndLocation(const PathDiagnosticLocation &L)
PathDiagnosticLocationPair(const PathDiagnosticLocation &start, const PathDiagnosticLocation &end)
void appendToDesc(StringRef S)
virtual PathGenerationScheme getGenerationScheme() const
PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
Create a location at an explicit offset in the source.
PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
Create a location corresponding to the given declaration.
void push_back(const PathDiagnosticLocationPair &X)
static bool classof(const PathDiagnosticPiece *P)
void Profile(llvm::FoldingSetNodeID &ID)
Used for profiling in the FoldingSet.
PathDiagnosticLocation getLocation() const override
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Definition: SemaDecl.cpp:13803
Used for HTML and text output.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:2472
Defines the clang::SourceLocation class and associated facilities.
PathPieces & getActivePath()
Return the path currently used by builders for constructing the PathDiagnostic.
bool isValid() const
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Definition: DiagnosticIDs.h:61
static bool classof(const PathDiagnosticPiece *P)
StringRef getTagStr() const
Return the string representation of the tag.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2290
A SourceLocation and its associated SourceManager.
PathDiagnosticLocation callEnterWithin
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
A trivial tuple used to represent a source range.
static bool classof(const PathDiagnosticPiece *P)
StackHintGeneratorForSymbol(SymbolRef S, StringRef M)
This class handles loading and caching of source files into memory.
static bool classof(const PathDiagnosticPiece *P)
StringRef getShortDescription() const
const Decl * getDeclWithIssue() const
Return the semantic context where an issue occurred.
void setEnd(const PathDiagnosticLocation &L)
static bool classof(const PathDiagnosticPiece *P)