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