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