clang  9.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  virtual bool supportsLogicalOpControlFlow() const { return false; }
129 
130  /// Return true if the PathDiagnosticConsumer supports individual
131  /// PathDiagnostics that span multiple files.
132  virtual bool supportsCrossFileDiagnostics() const { return false; }
133 
134 protected:
135  bool flushed = false;
136  llvm::FoldingSet<PathDiagnostic> Diags;
137 };
138 
139 //===----------------------------------------------------------------------===//
140 // Path-sensitive diagnostics.
141 //===----------------------------------------------------------------------===//
142 
144 public:
145  bool isPoint = false;
146 
147  PathDiagnosticRange(SourceRange R, bool isP = false)
148  : SourceRange(R), isPoint(isP) {}
149  PathDiagnosticRange() = default;
150 };
151 
153  llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
154 
156 private:
157  enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
158 
159  const Stmt *S = nullptr;
160  const Decl *D = nullptr;
161  const SourceManager *SM = nullptr;
164 
166  : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
167 
168  FullSourceLoc genLocation(
170  LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
171 
172  PathDiagnosticRange genRange(
173  LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
174 
175 public:
176  /// Create an invalid location.
177  PathDiagnosticLocation() = default;
178 
179  /// Create a location corresponding to the given statement.
182  : K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
183  S(K == StmtK ? s : nullptr), SM(&sm),
184  Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
185  assert(K == SingleLocK || S);
186  assert(K == SingleLocK || Loc.isValid());
187  assert(K == SingleLocK || Range.isValid());
188  }
189 
190  /// Create a location corresponding to the given declaration.
192  : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
193  assert(D);
194  assert(Loc.isValid());
195  assert(Range.isValid());
196  }
197 
198  /// Create a location at an explicit offset in the source.
199  ///
200  /// This should only be used if there are no more appropriate constructors.
202  : SM(&sm), Loc(loc, sm), Range(genRange()) {
203  assert(Loc.isValid());
204  assert(Range.isValid());
205  }
206 
207  /// Create a location corresponding to the given declaration.
209  const SourceManager &SM) {
210  return PathDiagnosticLocation(D, SM);
211  }
212 
213  /// Create a location for the beginning of the declaration.
214  static PathDiagnosticLocation createBegin(const Decl *D,
215  const SourceManager &SM);
216 
217  /// Create a location for the beginning of the declaration.
218  /// The third argument is ignored, useful for generic treatment
219  /// of statements and declarations.
221  createBegin(const Decl *D, const SourceManager &SM,
222  const LocationOrAnalysisDeclContext LAC) {
223  return createBegin(D, SM);
224  }
225 
226  /// Create a location for the beginning of the statement.
227  static PathDiagnosticLocation createBegin(const Stmt *S,
228  const SourceManager &SM,
230 
231  /// Create a location for the end of the statement.
232  ///
233  /// If the statement is a CompoundStatement, the location will point to the
234  /// closing brace instead of following it.
235  static PathDiagnosticLocation createEnd(const Stmt *S,
236  const SourceManager &SM,
238 
239  /// Create the location for the operator of the binary expression.
240  /// Assumes the statement has a valid location.
241  static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
242  const SourceManager &SM);
243  static PathDiagnosticLocation createConditionalColonLoc(
244  const ConditionalOperator *CO,
245  const SourceManager &SM);
246 
247  /// For member expressions, return the location of the '.' or '->'.
248  /// Assumes the statement has a valid location.
249  static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
250  const SourceManager &SM);
251 
252  /// Create a location for the beginning of the compound statement.
253  /// Assumes the statement has a valid location.
254  static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
255  const SourceManager &SM);
256 
257  /// Create a location for the end of the compound statement.
258  /// Assumes the statement has a valid location.
259  static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
260  const SourceManager &SM);
261 
262  /// Create a location for the beginning of the enclosing declaration body.
263  /// Defaults to the beginning of the first statement in the declaration body.
264  static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
265  const SourceManager &SM);
266 
267  /// Constructs a location for the end of the enclosing declaration body.
268  /// Defaults to the end of brace.
269  static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
270  const SourceManager &SM);
271 
272  /// Create a location corresponding to the given valid ExplodedNode.
274  const SourceManager &SMng);
275 
276  /// Create a location corresponding to the next valid ExplodedNode as end
277  /// of path location.
278  static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
279  const SourceManager &SM);
280 
281  /// Convert the given location into a single kind location.
282  static PathDiagnosticLocation createSingleLocation(
283  const PathDiagnosticLocation &PDL);
284 
285  bool operator==(const PathDiagnosticLocation &X) const {
286  return K == X.K && Loc == X.Loc && Range == X.Range;
287  }
288 
289  bool operator!=(const PathDiagnosticLocation &X) const {
290  return !(*this == X);
291  }
292 
293  bool isValid() const {
294  return SM != nullptr;
295  }
296 
298  return Loc;
299  }
300 
302  return Range;
303  }
304 
305  const Stmt *asStmt() const { assert(isValid()); return S; }
306  const Stmt *getStmtOrNull() const {
307  if (!isValid())
308  return nullptr;
309  return asStmt();
310  }
311 
312  const Decl *asDecl() const { assert(isValid()); return D; }
313 
314  bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
315 
316  bool hasValidLocation() const { return asLocation().isValid(); }
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, PopUp };
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.hasValidLocation() &&
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 || P->getKind() == PopUp;
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 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 
763 public:
765  bool AddPosRange = true)
766  : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
767  ~PathDiagnosticPopUpPiece() override;
768 
769  static bool classof(const PathDiagnosticPiece *P) {
770  return P->getKind() == PopUp;
771  }
772 
773  void dump() const override;
774 
775  void Profile(llvm::FoldingSetNodeID &ID) const override;
776 };
777 
778 /// File IDs mapped to sets of line numbers.
779 using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
780 
781 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
782 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
783 /// each which represent the pieces of the path.
784 class PathDiagnostic : public llvm::FoldingSetNode {
785  std::string CheckName;
786  const Decl *DeclWithIssue;
787  std::string BugType;
788  std::string VerboseDesc;
789  std::string ShortDesc;
790  std::string Category;
791  std::deque<std::string> OtherDesc;
792 
793  /// Loc The location of the path diagnostic report.
795 
796  PathPieces pathImpl;
798 
799  /// Important bug uniqueing location.
800  /// The location info is useful to differentiate between bugs.
801  PathDiagnosticLocation UniqueingLoc;
802  const Decl *UniqueingDecl;
803 
804  /// Lines executed in the path.
805  std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
806 
807 public:
808  PathDiagnostic() = delete;
809  PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue,
810  StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
811  StringRef category, PathDiagnosticLocation LocationToUnique,
812  const Decl *DeclToUnique,
813  std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
814  ~PathDiagnostic();
815 
816  const PathPieces &path;
817 
818  /// Return the path currently used by builders for constructing the
819  /// PathDiagnostic.
821  if (pathStack.empty())
822  return pathImpl;
823  return *pathStack.back();
824  }
825 
826  /// Return a mutable version of 'path'.
828  return pathImpl;
829  }
830 
831  /// Return the unrolled size of the path.
832  unsigned full_size();
833 
834  void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
835  void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
836 
837  bool isWithinCall() const { return !pathStack.empty(); }
838 
839  void setEndOfPath(std::shared_ptr<PathDiagnosticPiece> EndPiece) {
840  assert(!Loc.isValid() && "End location already set!");
841  Loc = EndPiece->getLocation();
842  assert(Loc.isValid() && "Invalid location for end-of-path piece");
843  getActivePath().push_back(std::move(EndPiece));
844  }
845 
846  void appendToDesc(StringRef S) {
847  if (!ShortDesc.empty())
848  ShortDesc += S;
849  VerboseDesc += S;
850  }
851 
852  /// If the last piece of the report point to the header file, resets
853  /// the location of the report to be the last location in the main source
854  /// file.
855  void resetDiagnosticLocationToMainFile();
856 
857  StringRef getVerboseDescription() const { return VerboseDesc; }
858 
859  StringRef getShortDescription() const {
860  return ShortDesc.empty() ? VerboseDesc : ShortDesc;
861  }
862 
863  StringRef getCheckName() const { return CheckName; }
864  StringRef getBugType() const { return BugType; }
865  StringRef getCategory() const { return Category; }
866 
867  /// Return the semantic context where an issue occurred. If the
868  /// issue occurs along a path, this represents the "central" area
869  /// where the bug manifests.
870  const Decl *getDeclWithIssue() const { return DeclWithIssue; }
871 
872  using meta_iterator = std::deque<std::string>::const_iterator;
873 
874  meta_iterator meta_begin() const { return OtherDesc.begin(); }
875  meta_iterator meta_end() const { return OtherDesc.end(); }
876  void addMeta(StringRef s) { OtherDesc.push_back(s); }
877 
879  return *ExecutedLines;
880  }
881 
883  return *ExecutedLines;
884  }
885 
887  return Loc;
888  }
889 
890  /// Get the location on which the report should be uniqued.
892  return UniqueingLoc;
893  }
894 
895  /// Get the declaration containing the uniqueing location.
896  const Decl *getUniqueingDecl() const {
897  return UniqueingDecl;
898  }
899 
901  Loc.flatten();
902  for (const auto &I : pathImpl)
903  I->flattenLocations();
904  }
905 
906  /// Profiles the diagnostic, independent of the path it references.
907  ///
908  /// This can be used to merge diagnostics that refer to the same issue
909  /// along different paths.
910  void Profile(llvm::FoldingSetNodeID &ID) const;
911 
912  /// Profiles the diagnostic, including its path.
913  ///
914  /// Two diagnostics with the same issue along different paths will generate
915  /// different profiles.
916  void FullProfile(llvm::FoldingSetNodeID &ID) const;
917 };
918 
919 } // namespace ento
920 
921 } // namespace clang
922 
923 #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
__m128i_u * p
Definition: emmintrin.h:2134
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:1712
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:3407
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:3705
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1303
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
__v2du d
Definition: emmintrin.h:413
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:1570
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:14125
Used for HTML, SARIF, and text output.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:2809
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:2518
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)