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