clang  12.0.0git
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 //===----------------------------------------------------------------------===//
56 // High-level interface for handlers of path-sensitive diagnostics.
57 //===----------------------------------------------------------------------===//
58 
59 class PathDiagnostic;
60 
61 /// These options tweak the behavior of path diangostic consumers.
62 /// Most of these options are currently supported by very few consumers.
64  /// Run-line of the tool that produced the diagnostic.
65  /// It can be included with the diagnostic for debugging purposes.
66  std::string ToolInvocation;
67 
68  /// Whether to include additional information about macro expansions
69  /// with the diagnostics, because otherwise they can be hard to obtain
70  /// without re-compiling the program under analysis.
72 
73  /// Whether to include LLVM statistics of the process in the diagnostic.
74  /// Useful for profiling the tool on large real-world codebases.
76 
77  /// If the consumer intends to produce multiple output files, should it
78  /// use randomly generated file names for these files (with the tiny risk of
79  /// having random collisions) or deterministic human-readable file names
80  /// (with a larger risk of deterministic collisions or invalid characters
81  /// in the file name). We should not really give this choice to the users
82  /// because deterministic mode is always superior when done right, but
83  /// for some consumers this mode is experimental and needs to be
84  /// off by default.
86 
87  /// Whether the consumer should treat consumed diagnostics as hard errors.
88  /// Useful for breaking your build when issues are found.
90 
91  /// Whether the consumer should attempt to rewrite the source file
92  /// with fix-it hints attached to the diagnostics it consumes.
94 
95  /// Whether the consumer should present the name of the entity that emitted
96  /// the diagnostic (eg., a checker) so that the user knew how to disable it.
98 
100 };
101 
103 public:
104  class PDFileEntry : public llvm::FoldingSetNode {
105  public:
106  PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
107 
108  using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
109 
110  /// A vector of <consumer,file> pairs.
112 
113  /// A precomputed hash tag used for uniquing PDFileEntry objects.
114  const llvm::FoldingSetNodeID NodeID;
115 
116  /// Used for profiling in the FoldingSet.
117  void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
118  };
119 
120  class FilesMade {
121  llvm::BumpPtrAllocator Alloc;
122  llvm::FoldingSet<PDFileEntry> Set;
123 
124  public:
125  ~FilesMade();
126 
127  bool empty() const { return Set.empty(); }
128 
129  void addDiagnostic(const PathDiagnostic &PD,
130  StringRef ConsumerName,
131  StringRef fileName);
132 
134  };
135 
136 private:
137  virtual void anchor();
138 
139 public:
140  PathDiagnosticConsumer() = default;
141  virtual ~PathDiagnosticConsumer();
142 
143  void FlushDiagnostics(FilesMade *FilesMade);
144 
145  virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
146  FilesMade *filesMade) = 0;
147 
148  virtual StringRef getName() const = 0;
149 
150  void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
151 
153  /// Only runs visitors, no output generated.
155 
156  /// Used for HTML, SARIF, and text output.
158 
159  /// Used for plist output, used for "arrows" generation.
161  };
162 
164 
166  return getGenerationScheme() != None;
167  }
168 
169  bool shouldAddPathEdges() const { return getGenerationScheme() == Extensive; }
170 
171  virtual bool supportsLogicalOpControlFlow() const { return false; }
172 
173  /// Return true if the PathDiagnosticConsumer supports individual
174  /// PathDiagnostics that span multiple files.
175  virtual bool supportsCrossFileDiagnostics() const { return false; }
176 
177 protected:
178  bool flushed = false;
179  llvm::FoldingSet<PathDiagnostic> Diags;
180 };
181 
182 //===----------------------------------------------------------------------===//
183 // Path-sensitive diagnostics.
184 //===----------------------------------------------------------------------===//
185 
187 public:
188  bool isPoint = false;
189 
190  PathDiagnosticRange(SourceRange R, bool isP = false)
191  : SourceRange(R), isPoint(isP) {}
192  PathDiagnosticRange() = default;
193 };
194 
196  llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
197 
199 private:
200  enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
201 
202  const Stmt *S = nullptr;
203  const Decl *D = nullptr;
204  const SourceManager *SM = nullptr;
207 
209  : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
210 
211  FullSourceLoc genLocation(
213  LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
214 
215  PathDiagnosticRange genRange(
216  LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
217 
218 public:
219  /// Create an invalid location.
220  PathDiagnosticLocation() = default;
221 
222  /// Create a location corresponding to the given statement.
225  : K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
226  S(K == StmtK ? s : nullptr), SM(&sm),
227  Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
228  assert(K == SingleLocK || S);
229  assert(K == SingleLocK || Loc.isValid());
230  assert(K == SingleLocK || Range.isValid());
231  }
232 
233  /// Create a location corresponding to the given declaration.
235  : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
236  assert(D);
237  assert(Loc.isValid());
238  assert(Range.isValid());
239  }
240 
241  /// Create a location at an explicit offset in the source.
242  ///
243  /// This should only be used if there are no more appropriate constructors.
245  : SM(&sm), Loc(loc, sm), Range(genRange()) {
246  assert(Loc.isValid());
247  assert(Range.isValid());
248  }
249 
250  /// Create a location corresponding to the given declaration.
252  const SourceManager &SM) {
253  return PathDiagnosticLocation(D, SM);
254  }
255 
256  /// Create a location for the beginning of the declaration.
257  static PathDiagnosticLocation createBegin(const Decl *D,
258  const SourceManager &SM);
259 
260  /// Create a location for the beginning of the declaration.
261  /// The third argument is ignored, useful for generic treatment
262  /// of statements and declarations.
264  createBegin(const Decl *D, const SourceManager &SM,
265  const LocationOrAnalysisDeclContext LAC) {
266  return createBegin(D, SM);
267  }
268 
269  /// Create a location for the beginning of the statement.
270  static PathDiagnosticLocation createBegin(const Stmt *S,
271  const SourceManager &SM,
273 
274  /// Create a location for the end of the statement.
275  ///
276  /// If the statement is a CompoundStatement, the location will point to the
277  /// closing brace instead of following it.
278  static PathDiagnosticLocation createEnd(const Stmt *S,
279  const SourceManager &SM,
281 
282  /// Create the location for the operator of the binary expression.
283  /// Assumes the statement has a valid location.
285  const SourceManager &SM);
287  const ConditionalOperator *CO,
288  const SourceManager &SM);
289 
290  /// For member expressions, return the location of the '.' or '->'.
291  /// Assumes the statement has a valid location.
293  const SourceManager &SM);
294 
295  /// Create a location for the beginning of the compound statement.
296  /// Assumes the statement has a valid location.
298  const SourceManager &SM);
299 
300  /// Create a location for the end of the compound statement.
301  /// Assumes the statement has a valid location.
303  const SourceManager &SM);
304 
305  /// Create a location for the beginning of the enclosing declaration body.
306  /// Defaults to the beginning of the first statement in the declaration body.
308  const SourceManager &SM);
309 
310  /// Constructs a location for the end of the enclosing declaration body.
311  /// Defaults to the end of brace.
313  const SourceManager &SM);
314 
315  /// Create a location corresponding to the given valid ProgramPoint.
317  const SourceManager &SMng);
318 
319  /// Convert the given location into a single kind location.
321  const PathDiagnosticLocation &PDL);
322 
323  /// Construct a source location that corresponds to either the beginning
324  /// or the end of the given statement, or a nearby valid source location
325  /// if the statement does not have a valid source location of its own.
326  static SourceLocation
328  bool UseEndOfStatement = false);
329 
330  bool operator==(const PathDiagnosticLocation &X) const {
331  return K == X.K && Loc == X.Loc && Range == X.Range;
332  }
333 
334  bool operator!=(const PathDiagnosticLocation &X) const {
335  return !(*this == X);
336  }
337 
338  bool isValid() const {
339  return SM != nullptr;
340  }
341 
343  return Loc;
344  }
345 
347  return Range;
348  }
349 
350  const Stmt *asStmt() const { assert(isValid()); return S; }
351  const Stmt *getStmtOrNull() const {
352  if (!isValid())
353  return nullptr;
354  return asStmt();
355  }
356 
357  const Decl *asDecl() const { assert(isValid()); return D; }
358 
359  bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
360 
361  bool hasValidLocation() const { return asLocation().isValid(); }
362 
363  void invalidate() {
364  *this = PathDiagnosticLocation();
365  }
366 
367  void flatten();
368 
369  const SourceManager& getManager() const { assert(isValid()); return *SM; }
370 
371  void Profile(llvm::FoldingSetNodeID &ID) const;
372 
373  void dump() const;
374 };
375 
377 private:
378  PathDiagnosticLocation Start, End;
379 
380 public:
382  const PathDiagnosticLocation &end)
383  : Start(start), End(end) {}
384 
385  const PathDiagnosticLocation &getStart() const { return Start; }
386  const PathDiagnosticLocation &getEnd() const { return End; }
387 
388  void setStart(const PathDiagnosticLocation &L) { Start = L; }
389  void setEnd(const PathDiagnosticLocation &L) { End = L; }
390 
391  void flatten() {
392  Start.flatten();
393  End.flatten();
394  }
395 
396  void Profile(llvm::FoldingSetNodeID &ID) const {
397  Start.Profile(ID);
398  End.Profile(ID);
399  }
400 };
401 
402 //===----------------------------------------------------------------------===//
403 // Path "pieces" for path-sensitive diagnostics.
404 //===----------------------------------------------------------------------===//
405 
406 class PathDiagnosticPiece: public llvm::FoldingSetNode {
407 public:
410 
411 private:
412  const std::string str;
413  const Kind kind;
414  const DisplayHint Hint;
415 
416  /// In the containing bug report, this piece is the last piece from
417  /// the main source file.
418  bool LastInMainSourceFile = false;
419 
420  /// A constant string that can be used to tag the PathDiagnosticPiece,
421  /// typically with the identification of the creator. The actual pointer
422  /// value is meant to be an identifier; the string itself is useful for
423  /// debugging.
424  StringRef Tag;
425 
426  std::vector<SourceRange> ranges;
427  std::vector<FixItHint> fixits;
428 
429 protected:
430  PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
432 
433 public:
434  PathDiagnosticPiece() = delete;
435  PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
437  virtual ~PathDiagnosticPiece();
438 
439  StringRef getString() const { return str; }
440 
441  /// Tag this PathDiagnosticPiece with the given C-string.
442  void setTag(const char *tag) { Tag = tag; }
443 
444  /// Return the opaque tag (if any) on the PathDiagnosticPiece.
445  const void *getTag() const { return Tag.data(); }
446 
447  /// Return the string representation of the tag. This is useful
448  /// for debugging.
449  StringRef getTagStr() const { return Tag; }
450 
451  /// getDisplayHint - Return a hint indicating where the diagnostic should
452  /// be displayed by the PathDiagnosticConsumer.
453  DisplayHint getDisplayHint() const { return Hint; }
454 
455  virtual PathDiagnosticLocation getLocation() const = 0;
456  virtual void flattenLocations() = 0;
457 
458  Kind getKind() const { return kind; }
459 
461  if (!R.isValid())
462  return;
463  ranges.push_back(R);
464  }
465 
467  if (!B.isValid() || !E.isValid())
468  return;
469  ranges.push_back(SourceRange(B,E));
470  }
471 
472  void addFixit(FixItHint F) {
473  fixits.push_back(F);
474  }
475 
476  /// Return the SourceRanges associated with this PathDiagnosticPiece.
477  ArrayRef<SourceRange> getRanges() const { return ranges; }
478 
479  /// Return the fix-it hints associated with this PathDiagnosticPiece.
480  ArrayRef<FixItHint> getFixits() const { return fixits; }
481 
482  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
483 
485  LastInMainSourceFile = true;
486  }
487 
488  bool isLastInMainSourceFile() const {
489  return LastInMainSourceFile;
490  }
491 
492  virtual void dump() const = 0;
493 };
494 
495 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
496 
497 class PathPieces : public std::list<PathDiagnosticPieceRef> {
498  void flattenTo(PathPieces &Primary, PathPieces &Current,
499  bool ShouldFlattenMacros) const;
500 
501 public:
502  PathPieces flatten(bool ShouldFlattenMacros) const {
503  PathPieces Result;
504  flattenTo(Result, Result, ShouldFlattenMacros);
505  return Result;
506  }
507 
508  void dump() const;
509 };
510 
512 private:
514 
515 public:
517  StringRef s,
519  bool addPosRange = true)
520  : PathDiagnosticPiece(s, k), Pos(pos) {
521  assert(Pos.isValid() && Pos.hasValidLocation() &&
522  "PathDiagnosticSpotPiece's must have a valid location.");
523  if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
524  }
525 
526  PathDiagnosticLocation getLocation() const override { return Pos; }
527  void flattenLocations() override { Pos.flatten(); }
528 
529  void Profile(llvm::FoldingSetNodeID &ID) const override;
530 
531  static bool classof(const PathDiagnosticPiece *P) {
532  return P->getKind() == Event || P->getKind() == Macro ||
533  P->getKind() == Note || P->getKind() == PopUp;
534  }
535 };
536 
538  Optional<bool> IsPrunable;
539 
540 public:
542  StringRef s, bool addPosRange = true)
543  : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
544  ~PathDiagnosticEventPiece() override;
545 
546  /// Mark the diagnostic piece as being potentially prunable. This
547  /// flag may have been previously set, at which point it will not
548  /// be reset unless one specifies to do so.
549  void setPrunable(bool isPrunable, bool override = false) {
550  if (IsPrunable.hasValue() && !override)
551  return;
552  IsPrunable = isPrunable;
553  }
554 
555  /// Return true if the diagnostic piece is prunable.
556  bool isPrunable() const {
557  return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
558  }
559 
560  void dump() const override;
561 
562  static bool classof(const PathDiagnosticPiece *P) {
563  return P->getKind() == Event;
564  }
565 };
566 
568  const Decl *Caller;
569  const Decl *Callee = nullptr;
570 
571  // Flag signifying that this diagnostic has only call enter and no matching
572  // call exit.
573  bool NoExit;
574 
575  // Flag signifying that the callee function is an Objective-C autosynthesized
576  // property getter or setter.
577  bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
578 
579  // The custom string, which should appear after the call Return Diagnostic.
580  // TODO: Should we allow multiple diagnostics?
581  std::string CallStackMessage;
582 
583  PathDiagnosticCallPiece(const Decl *callerD,
584  const PathDiagnosticLocation &callReturnPos)
585  : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
586  callReturn(callReturnPos) {}
587  PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
588  : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
589  path(oldPath) {}
590 
591 public:
596 
597  ~PathDiagnosticCallPiece() override;
598 
599  const Decl *getCaller() const { return Caller; }
600 
601  const Decl *getCallee() const { return Callee; }
602  void setCallee(const CallEnter &CE, const SourceManager &SM);
603 
604  bool hasCallStackMessage() { return !CallStackMessage.empty(); }
605  void setCallStackMessage(StringRef st) { CallStackMessage = std::string(st); }
606 
607  PathDiagnosticLocation getLocation() const override { return callEnter; }
608 
609  std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
610  std::shared_ptr<PathDiagnosticEventPiece>
612  std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
613 
614  void flattenLocations() override {
615  callEnter.flatten();
617  for (const auto &I : path)
618  I->flattenLocations();
619  }
620 
621  static std::shared_ptr<PathDiagnosticCallPiece>
622  construct(const CallExitEnd &CE,
623  const SourceManager &SM);
624 
626  const Decl *caller);
627 
628  void dump() const override;
629 
630  void Profile(llvm::FoldingSetNodeID &ID) const override;
631 
632  static bool classof(const PathDiagnosticPiece *P) {
633  return P->getKind() == Call;
634  }
635 };
636 
638  std::vector<PathDiagnosticLocationPair> LPairs;
639 
640 public:
642  const PathDiagnosticLocation &endPos,
643  StringRef s)
645  LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
646  }
647 
649  const PathDiagnosticLocation &endPos)
651  LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
652  }
653 
655 
657  assert(!LPairs.empty() &&
658  "PathDiagnosticControlFlowPiece needs at least one location.");
659  return LPairs[0].getStart();
660  }
661 
663  assert(!LPairs.empty() &&
664  "PathDiagnosticControlFlowPiece needs at least one location.");
665  return LPairs[0].getEnd();
666  }
667 
669  LPairs[0].setStart(L);
670  }
671 
673  LPairs[0].setEnd(L);
674  }
675 
676  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
677 
679  return getStartLocation();
680  }
681 
682  using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
683 
684  iterator begin() { return LPairs.begin(); }
685  iterator end() { return LPairs.end(); }
686 
687  void flattenLocations() override {
688  for (auto &I : *this)
689  I.flatten();
690  }
691 
692  using const_iterator =
693  std::vector<PathDiagnosticLocationPair>::const_iterator;
694 
695  const_iterator begin() const { return LPairs.begin(); }
696  const_iterator end() const { return LPairs.end(); }
697 
698  static bool classof(const PathDiagnosticPiece *P) {
699  return P->getKind() == ControlFlow;
700  }
701 
702  void dump() const override;
703 
704  void Profile(llvm::FoldingSetNodeID &ID) const override;
705 };
706 
708 public:
710  : PathDiagnosticSpotPiece(pos, "", Macro) {}
711  ~PathDiagnosticMacroPiece() override;
712 
714 
715  void flattenLocations() override {
717  for (const auto &I : subPieces)
718  I->flattenLocations();
719  }
720 
721  static bool classof(const PathDiagnosticPiece *P) {
722  return P->getKind() == Macro;
723  }
724 
725  void dump() const override;
726 
727  void Profile(llvm::FoldingSetNodeID &ID) const override;
728 };
729 
731 public:
733  bool AddPosRange = true)
734  : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
735  ~PathDiagnosticNotePiece() override;
736 
737  static bool classof(const PathDiagnosticPiece *P) {
738  return P->getKind() == Note;
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, PopUp, AddPosRange) {}
751  ~PathDiagnosticPopUpPiece() override;
752 
753  static bool classof(const PathDiagnosticPiece *P) {
754  return P->getKind() == PopUp;
755  }
756 
757  void dump() const override;
758 
759  void Profile(llvm::FoldingSetNodeID &ID) const override;
760 };
761 
762 /// File IDs mapped to sets of line numbers.
763 using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
764 
765 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
766 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
767 /// each which represent the pieces of the path.
768 class PathDiagnostic : public llvm::FoldingSetNode {
769  std::string CheckerName;
770  const Decl *DeclWithIssue;
771  std::string BugType;
772  std::string VerboseDesc;
773  std::string ShortDesc;
774  std::string Category;
775  std::deque<std::string> OtherDesc;
776 
777  /// Loc The location of the path diagnostic report.
779 
780  PathPieces pathImpl;
782 
783  /// Important bug uniqueing location.
784  /// The location info is useful to differentiate between bugs.
785  PathDiagnosticLocation UniqueingLoc;
786  const Decl *UniqueingDecl;
787 
788  /// Lines executed in the path.
789  std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
790 
791 public:
792  PathDiagnostic() = delete;
793  PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
794  StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
795  StringRef category, PathDiagnosticLocation LocationToUnique,
796  const Decl *DeclToUnique,
797  std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
798  ~PathDiagnostic();
799 
800  const PathPieces &path;
801 
802  /// Return the path currently used by builders for constructing the
803  /// PathDiagnostic.
805  if (pathStack.empty())
806  return pathImpl;
807  return *pathStack.back();
808  }
809 
810  /// Return a mutable version of 'path'.
812  return pathImpl;
813  }
814 
815  /// Return the unrolled size of the path.
816  unsigned full_size();
817 
818  void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
819  void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
820 
821  bool isWithinCall() const { return !pathStack.empty(); }
822 
824  assert(!Loc.isValid() && "End location already set!");
825  Loc = EndPiece->getLocation();
826  assert(Loc.isValid() && "Invalid location for end-of-path piece");
827  getActivePath().push_back(std::move(EndPiece));
828  }
829 
830  void appendToDesc(StringRef S) {
831  if (!ShortDesc.empty())
832  ShortDesc += S;
833  VerboseDesc += S;
834  }
835 
836  StringRef getVerboseDescription() const { return VerboseDesc; }
837 
838  StringRef getShortDescription() const {
839  return ShortDesc.empty() ? VerboseDesc : ShortDesc;
840  }
841 
842  StringRef getCheckerName() const { return CheckerName; }
843  StringRef getBugType() const { return BugType; }
844  StringRef getCategory() const { return Category; }
845 
846  using meta_iterator = std::deque<std::string>::const_iterator;
847 
848  meta_iterator meta_begin() const { return OtherDesc.begin(); }
849  meta_iterator meta_end() const { return OtherDesc.end(); }
850  void addMeta(StringRef s) { OtherDesc.push_back(std::string(s)); }
851 
853  return *ExecutedLines;
854  }
855 
857  return *ExecutedLines;
858  }
859 
860  /// Return the semantic context where an issue occurred. If the
861  /// issue occurs along a path, this represents the "central" area
862  /// where the bug manifests.
863  const Decl *getDeclWithIssue() const { return DeclWithIssue; }
864 
865  void setDeclWithIssue(const Decl *D) {
866  DeclWithIssue = D;
867  }
868 
870  return Loc;
871  }
872 
874  Loc = NewLoc;
875  }
876 
877  /// Get the location on which the report should be uniqued.
879  return UniqueingLoc;
880  }
881 
882  /// Get the declaration containing the uniqueing location.
883  const Decl *getUniqueingDecl() const {
884  return UniqueingDecl;
885  }
886 
888  Loc.flatten();
889  for (const auto &I : pathImpl)
890  I->flattenLocations();
891  }
892 
893  /// Profiles the diagnostic, independent of the path it references.
894  ///
895  /// This can be used to merge diagnostics that refer to the same issue
896  /// along different paths.
897  void Profile(llvm::FoldingSetNodeID &ID) const;
898 
899  /// Profiles the diagnostic, including its path.
900  ///
901  /// Two diagnostics with the same issue along different paths will generate
902  /// different profiles.
903  void FullProfile(llvm::FoldingSetNodeID &ID) const;
904 };
905 
906 } // namespace ento
907 } // namespace clang
908 
909 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
static bool classof(const PathDiagnosticPiece *P)
PathDiagnosticPiece & operator=(const PathDiagnosticPiece &)=delete
PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, StringRef s, PathDiagnosticPiece::Kind k, bool addPosRange=true)
These options tweak the behavior of path diangostic consumers.
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:68
void setLocation(PathDiagnosticLocation NewLoc)
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
virtual StringRef getName() const =0
Represents a point when we begin processing an inlined call.
Definition: ProgramPoint.h:630
static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the beginning of the compound statement.
bool ShouldSerializeStats
Whether to include LLVM statistics of the process in the diagnostic.
StringRef P
void Profile(llvm::FoldingSetNodeID &ID) const
Profiles the diagnostic, independent of the path it references.
std::shared_ptr< PathDiagnosticEventPiece > getCallEnterWithinCallerEvent() const
void Profile(llvm::FoldingSetNodeID &ID) const
A Range represents the closed range [from, to].
PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
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
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
bool ShouldDisplayMacroExpansions
Whether to include additional information about macro expansions with the diagnostics,...
const PathDiagnosticLocation & getEnd() const
bool operator==(const PathDiagnosticLocation &X) const
meta_iterator meta_begin() const
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
const FilesToLineNumsMap & getExecutedLines() const
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
PathDiagnosticLocation getLocation() const
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, method or block under analysis.
static bool classof(const PathDiagnosticPiece *P)
StringRef getVerboseDescription() const
void pushActivePath(PathPieces *p)
int Category
Definition: Format.cpp:2073
FilesToLineNumsMap & getExecutedLines()
bool ShouldApplyFixIts
Whether the consumer should attempt to rewrite the source file with fix-it hints attached to the diag...
void Profile(llvm::FoldingSetNodeID &ID) const override
virtual bool supportsLogicalOpControlFlow() const
PathPieces & getMutablePieces()
Return a mutable version of 'path'.
std::string ToolInvocation
Run-line of the tool that produced the diagnostic.
PDFileEntry(llvm::FoldingSetNodeID &NodeID)
llvm::FoldingSet< PathDiagnostic > Diags
void setStart(const PathDiagnosticLocation &L)
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
void Profile(llvm::FoldingSetNodeID &ID) const override
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3727
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.
PathDiagnosticLocation(const Stmt *s, const SourceManager &sm, LocationOrAnalysisDeclContext lac)
Create a location corresponding to the given statement.
virtual PathDiagnosticLocation getLocation() const =0
__device__ __2f16 float bool s
PathDiagnosticLocation getEndLocation() const
static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, const SourceManager &SM)
For member expressions, return the location of the '.
ConditionalOperator - The ?: ternary operator.
Definition: Expr.h:4065
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1398
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)
static SourceLocation getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement=false)
Construct a source location that corresponds to either the beginning or the end of the given statemen...
PDFileEntry::ConsumerFiles * getFiles(const PathDiagnostic &PD)
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...
void FullProfile(llvm::FoldingSetNodeID &ID) const
Profiles the diagnostic, including its path.
bool isPrunable() const
Return true if the diagnostic piece is prunable.
StringRef getCheckerName() const
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)
#define SM(sm)
Definition: Cuda.cpp:62
bool isValid() const =delete
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
PathPieces flatten(bool ShouldFlattenMacros) const
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
StringRef getCategory() const
Only runs visitors, no output generated.
static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, const SourceManager &SM)
Create a location for the beginning of the enclosing declaration body.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, StringRef s, bool addPosRange=true)
std::shared_ptr< PathDiagnosticEventPiece > getCallEnterEvent() const
const llvm::FoldingSetNodeID NodeID
A precomputed hash tag used for uniquing PDFileEntry objects.
Kind
virtual void FlushDiagnosticsImpl(std::vector< const PathDiagnostic * > &Diags, FilesMade *filesMade)=0
void Profile(llvm::FoldingSetNodeID &ID) const
bool ShouldDisplayWarningsAsErrors
Whether the consumer should treat consumed diagnostics as hard errors.
Encodes a location in the source.
std::shared_ptr< PathDiagnosticEventPiece > getCallExitEvent() const
void setCallee(const CallEnter &CE, const SourceManager &SM)
std::deque< std::string >::const_iterator meta_iterator
static PathDiagnosticLocation createConditionalColonLoc(const ConditionalOperator *CO, const SourceManager &SM)
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the end of the statement.
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.
virtual void dump() const =0
Dataflow Directional Tag Classes.
const PathDiagnosticLocation & getStart() const
bool isValid() const
Return true if this is a valid SourceLocation object.
virtual void Profile(llvm::FoldingSetNodeID &ID) const
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, const PathDiagnosticLocation &endPos)
void FlushDiagnostics(FilesMade *FilesMade)
PathDiagnosticRange asRange() const
PathDiagnosticLocation()=default
Create an invalid location.
void Profile(llvm::FoldingSetNodeID &ID) const override
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)
ArrayRef< FixItHint > getFixits() const
Return the fix-it hints associated with this PathDiagnosticPiece.
static bool classof(const PathDiagnosticPiece *P)
void Profile(llvm::FoldingSetNodeID &ID) const override
static std::shared_ptr< PathDiagnosticCallPiece > construct(const CallExitEnd &CE, const SourceManager &SM)
void Profile(llvm::FoldingSetNodeID &ID)
Used for profiling in the FoldingSet.
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
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:15282
Used for HTML, SARIF, and text output.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3086
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.
A SourceLocation and its associated SourceManager.
PathDiagnosticLocation callEnterWithin
void Profile(llvm::FoldingSetNodeID &ID) const override
void addDiagnostic(const PathDiagnostic &PD, StringRef ConsumerName, StringRef fileName)
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
Definition: Diagnostic.h:70
A trivial tuple used to represent a source range.
void setDeclWithIssue(const Decl *D)
static bool classof(const PathDiagnosticPiece *P)
bool ShouldDisplayDiagnosticName
Whether the consumer should present the name of the entity that emitted the diagnostic (eg....
bool ShouldWriteStableReportFilename
If the consumer intends to produce multiple output files, should it use randomly generated file names...
This class handles loading and caching of source files into memory.
static bool classof(const PathDiagnosticPiece *P)
unsigned full_size()
Return the unrolled size of the path.
void Profile(llvm::FoldingSetNodeID &ID) const override
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)