Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===- BugReporter.h - Generate PathDiagnostics -----------------*- 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 BugReporter, a utility class for generating
  10. //  PathDiagnostics for analyses based on ProgramState.
  11. //
  12. //===----------------------------------------------------------------------===//
  13.  
  14. #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
  15. #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
  16.  
  17. #include "clang/Analysis/PathDiagnostic.h"
  18. #include "clang/Basic/LLVM.h"
  19. #include "clang/Basic/SourceLocation.h"
  20. #include "clang/Lex/Preprocessor.h"
  21. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
  22. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  23. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
  25. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
  26. #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
  27. #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
  28. #include "llvm/ADT/ArrayRef.h"
  29. #include "llvm/ADT/DenseSet.h"
  30. #include "llvm/ADT/FoldingSet.h"
  31. #include "llvm/ADT/ImmutableSet.h"
  32. #include "llvm/ADT/SmallSet.h"
  33. #include "llvm/ADT/SmallVector.h"
  34. #include "llvm/ADT/StringMap.h"
  35. #include "llvm/ADT/StringRef.h"
  36. #include "llvm/ADT/ilist.h"
  37. #include "llvm/ADT/ilist_node.h"
  38. #include "llvm/ADT/iterator_range.h"
  39. #include <cassert>
  40. #include <memory>
  41. #include <optional>
  42. #include <string>
  43. #include <utility>
  44. #include <vector>
  45.  
  46. namespace clang {
  47.  
  48. class AnalyzerOptions;
  49. class ASTContext;
  50. class Decl;
  51. class LocationContext;
  52. class SourceManager;
  53. class Stmt;
  54.  
  55. namespace ento {
  56.  
  57. class BugType;
  58. class CheckerBase;
  59. class ExplodedGraph;
  60. class ExplodedNode;
  61. class ExprEngine;
  62. class MemRegion;
  63.  
  64. //===----------------------------------------------------------------------===//
  65. // Interface for individual bug reports.
  66. //===----------------------------------------------------------------------===//
  67.  
  68. /// A mapping from diagnostic consumers to the diagnostics they should
  69. /// consume.
  70. using DiagnosticForConsumerMapTy =
  71.     llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>;
  72.  
  73. /// Interface for classes constructing Stack hints.
  74. ///
  75. /// If a PathDiagnosticEvent occurs in a different frame than the final
  76. /// diagnostic the hints can be used to summarize the effect of the call.
  77. class StackHintGenerator {
  78. public:
  79.   virtual ~StackHintGenerator() = 0;
  80.  
  81.   /// Construct the Diagnostic message for the given ExplodedNode.
  82.   virtual std::string getMessage(const ExplodedNode *N) = 0;
  83. };
  84.  
  85. /// Constructs a Stack hint for the given symbol.
  86. ///
  87. /// The class knows how to construct the stack hint message based on
  88. /// traversing the CallExpr associated with the call and checking if the given
  89. /// symbol is returned or is one of the arguments.
  90. /// The hint can be customized by redefining 'getMessageForX()' methods.
  91. class StackHintGeneratorForSymbol : public StackHintGenerator {
  92. private:
  93.   SymbolRef Sym;
  94.   std::string Msg;
  95.  
  96. public:
  97.   StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
  98.   ~StackHintGeneratorForSymbol() override = default;
  99.  
  100.   /// Search the call expression for the symbol Sym and dispatch the
  101.   /// 'getMessageForX()' methods to construct a specific message.
  102.   std::string getMessage(const ExplodedNode *N) override;
  103.  
  104.   /// Produces the message of the following form:
  105.   ///   'Msg via Nth parameter'
  106.   virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
  107.  
  108.   virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
  109.     return Msg;
  110.   }
  111.  
  112.   virtual std::string getMessageForSymbolNotFound() {
  113.     return Msg;
  114.   }
  115. };
  116.  
  117. /// This class provides an interface through which checkers can create
  118. /// individual bug reports.
  119. class BugReport {
  120. public:
  121.   enum class Kind { Basic, PathSensitive };
  122.  
  123. protected:
  124.   friend class BugReportEquivClass;
  125.   friend class BugReporter;
  126.  
  127.   Kind K;
  128.   const BugType& BT;
  129.   std::string ShortDescription;
  130.   std::string Description;
  131.  
  132.   SmallVector<SourceRange, 4> Ranges;
  133.   SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> Notes;
  134.   SmallVector<FixItHint, 4> Fixits;
  135.  
  136.   BugReport(Kind kind, const BugType &bt, StringRef desc)
  137.       : BugReport(kind, bt, "", desc) {}
  138.  
  139.   BugReport(Kind K, const BugType &BT, StringRef ShortDescription,
  140.             StringRef Description)
  141.       : K(K), BT(BT), ShortDescription(ShortDescription),
  142.         Description(Description) {}
  143.  
  144. public:
  145.   virtual ~BugReport() = default;
  146.  
  147.   Kind getKind() const { return K; }
  148.  
  149.   const BugType& getBugType() const { return BT; }
  150.  
  151.   /// A verbose warning message that is appropriate for displaying next to
  152.   /// the source code that introduces the problem. The description should be
  153.   /// at least a full sentence starting with a capital letter. The period at
  154.   /// the end of the warning is traditionally omitted. If the description
  155.   /// consists of multiple sentences, periods between the sentences are
  156.   /// encouraged, but the period at the end of the description is still omitted.
  157.   StringRef getDescription() const { return Description; }
  158.  
  159.   /// A short general warning message that is appropriate for displaying in
  160.   /// the list of all reported bugs. It should describe what kind of bug is found
  161.   /// but does not need to try to go into details of that specific bug.
  162.   /// Grammatical conventions of getDescription() apply here as well.
  163.   StringRef getShortDescription(bool UseFallback = true) const {
  164.     if (ShortDescription.empty() && UseFallback)
  165.       return Description;
  166.     return ShortDescription;
  167.   }
  168.  
  169.   /// The primary location of the bug report that points at the undesirable
  170.   /// behavior in the code. UIs should attach the warning description to this
  171.   /// location. The warning description should describe the bad behavior
  172.   /// at this location.
  173.   virtual PathDiagnosticLocation getLocation() const = 0;
  174.  
  175.   /// The smallest declaration that contains the bug location.
  176.   /// This is purely cosmetic; the declaration can be displayed to the user
  177.   /// but it does not affect whether the report is emitted.
  178.   virtual const Decl *getDeclWithIssue() const = 0;
  179.  
  180.   /// Get the location on which the report should be uniqued. Two warnings are
  181.   /// considered to be equivalent whenever they have the same bug types,
  182.   /// descriptions, and uniqueing locations. Out of a class of equivalent
  183.   /// warnings only one gets displayed to the user. For most warnings the
  184.   /// uniqueing location coincides with their location, but sometimes
  185.   /// it makes sense to use different locations. For example, a leak
  186.   /// checker can place the warning at the location where the last reference
  187.   /// to the leaking resource is dropped but at the same time unique the warning
  188.   /// by where that resource is acquired (allocated).
  189.   virtual PathDiagnosticLocation getUniqueingLocation() const = 0;
  190.  
  191.   /// Get the declaration that corresponds to (usually contains) the uniqueing
  192.   /// location. This is not actively used for uniqueing, i.e. otherwise
  193.   /// identical reports that have different uniqueing decls will be considered
  194.   /// equivalent.
  195.   virtual const Decl *getUniqueingDecl() const = 0;
  196.  
  197.   /// Add new item to the list of additional notes that need to be attached to
  198.   /// this report. If the report is path-sensitive, these notes will not be
  199.   /// displayed as part of the execution path explanation, but will be displayed
  200.   /// separately. Use bug visitors if you need to add an extra path note.
  201.   void addNote(StringRef Msg, const PathDiagnosticLocation &Pos,
  202.                ArrayRef<SourceRange> Ranges = {}) {
  203.     auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg);
  204.  
  205.     for (const auto &R : Ranges)
  206.       P->addRange(R);
  207.  
  208.     Notes.push_back(std::move(P));
  209.   }
  210.  
  211.   ArrayRef<std::shared_ptr<PathDiagnosticNotePiece>> getNotes() {
  212.     return Notes;
  213.   }
  214.  
  215.   /// Add a range to a bug report.
  216.   ///
  217.   /// Ranges are used to highlight regions of interest in the source code.
  218.   /// They should be at the same source code line as the BugReport location.
  219.   /// By default, the source range of the statement corresponding to the error
  220.   /// node will be used; add a single invalid range to specify absence of
  221.   /// ranges.
  222.   void addRange(SourceRange R) {
  223.     assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
  224.                            "to specify that the report does not have a range.");
  225.     Ranges.push_back(R);
  226.   }
  227.  
  228.   /// Get the SourceRanges associated with the report.
  229.   virtual ArrayRef<SourceRange> getRanges() const {
  230.     return Ranges;
  231.   }
  232.  
  233.   /// Add a fix-it hint to the bug report.
  234.   ///
  235.   /// Fix-it hints are the suggested edits to the code that would resolve
  236.   /// the problem explained by the bug report. Fix-it hints should be
  237.   /// as conservative as possible because it is not uncommon for the user
  238.   /// to blindly apply all fixits to their project. Note that it is very hard
  239.   /// to produce a good fix-it hint for most path-sensitive warnings.
  240.   void addFixItHint(const FixItHint &F) {
  241.     Fixits.push_back(F);
  242.   }
  243.  
  244.   llvm::ArrayRef<FixItHint> getFixits() const { return Fixits; }
  245.  
  246.   /// Reports are uniqued to ensure that we do not emit multiple diagnostics
  247.   /// for each bug.
  248.   virtual void Profile(llvm::FoldingSetNodeID& hash) const = 0;
  249. };
  250.  
  251. class BasicBugReport : public BugReport {
  252.   PathDiagnosticLocation Location;
  253.   const Decl *DeclWithIssue = nullptr;
  254.  
  255. public:
  256.   BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l)
  257.       : BugReport(Kind::Basic, bt, desc), Location(l) {}
  258.  
  259.   static bool classof(const BugReport *R) {
  260.     return R->getKind() == Kind::Basic;
  261.   }
  262.  
  263.   PathDiagnosticLocation getLocation() const override {
  264.     assert(Location.isValid());
  265.     return Location;
  266.   }
  267.  
  268.   const Decl *getDeclWithIssue() const override {
  269.     return DeclWithIssue;
  270.   }
  271.  
  272.   PathDiagnosticLocation getUniqueingLocation() const override {
  273.     return getLocation();
  274.   }
  275.  
  276.   const Decl *getUniqueingDecl() const override {
  277.     return getDeclWithIssue();
  278.   }
  279.  
  280.   /// Specifically set the Decl where an issue occurred. This isn't necessary
  281.   /// for BugReports that cover a path as it will be automatically inferred.
  282.   void setDeclWithIssue(const Decl *declWithIssue) {
  283.     DeclWithIssue = declWithIssue;
  284.   }
  285.  
  286.   void Profile(llvm::FoldingSetNodeID& hash) const override;
  287. };
  288.  
  289. class PathSensitiveBugReport : public BugReport {
  290. public:
  291.   using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>;
  292.   using visitor_iterator = VisitorList::iterator;
  293.   using visitor_range = llvm::iterator_range<visitor_iterator>;
  294.  
  295. protected:
  296.   /// The ExplodedGraph node against which the report was thrown. It corresponds
  297.   /// to the end of the execution path that demonstrates the bug.
  298.   const ExplodedNode *ErrorNode = nullptr;
  299.  
  300.   /// The range that corresponds to ErrorNode's program point. It is usually
  301.   /// highlighted in the report.
  302.   const SourceRange ErrorNodeRange;
  303.  
  304.   /// Profile to identify equivalent bug reports for error report coalescing.
  305.  
  306.   /// A (stack of) a set of symbols that are registered with this
  307.   /// report as being "interesting", and thus used to help decide which
  308.   /// diagnostics to include when constructing the final path diagnostic.
  309.   /// The stack is largely used by BugReporter when generating PathDiagnostics
  310.   /// for multiple PathDiagnosticConsumers.
  311.   llvm::DenseMap<SymbolRef, bugreporter::TrackingKind> InterestingSymbols;
  312.  
  313.   /// A (stack of) set of regions that are registered with this report as being
  314.   /// "interesting", and thus used to help decide which diagnostics
  315.   /// to include when constructing the final path diagnostic.
  316.   /// The stack is largely used by BugReporter when generating PathDiagnostics
  317.   /// for multiple PathDiagnosticConsumers.
  318.   llvm::DenseMap<const MemRegion *, bugreporter::TrackingKind>
  319.       InterestingRegions;
  320.  
  321.   /// A set of location contexts that correspoind to call sites which should be
  322.   /// considered "interesting".
  323.   llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts;
  324.  
  325.   /// A set of custom visitors which generate "event" diagnostics at
  326.   /// interesting points in the path.
  327.   VisitorList Callbacks;
  328.  
  329.   /// Used for ensuring the visitors are only added once.
  330.   llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
  331.  
  332.   /// When set, this flag disables all callstack pruning from a diagnostic
  333.   /// path.  This is useful for some reports that want maximum fidelty
  334.   /// when reporting an issue.
  335.   bool DoNotPrunePath = false;
  336.  
  337.   /// Used to track unique reasons why a bug report might be invalid.
  338.   ///
  339.   /// \sa markInvalid
  340.   /// \sa removeInvalidation
  341.   using InvalidationRecord = std::pair<const void *, const void *>;
  342.  
  343.   /// If non-empty, this bug report is likely a false positive and should not be
  344.   /// shown to the user.
  345.   ///
  346.   /// \sa markInvalid
  347.   /// \sa removeInvalidation
  348.   llvm::SmallSet<InvalidationRecord, 4> Invalidations;
  349.  
  350.   /// Conditions we're already tracking.
  351.   llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions;
  352.  
  353.   /// Reports with different uniqueing locations are considered to be different
  354.   /// for the purposes of deduplication.
  355.   PathDiagnosticLocation UniqueingLocation;
  356.   const Decl *UniqueingDecl;
  357.  
  358.   const Stmt *getStmt() const;
  359.  
  360.   /// If an event occurs in a different frame than the final diagnostic,
  361.   /// supply a message that will be used to construct an extra hint on the
  362.   /// returns from all the calls on the stack from this event to the final
  363.   /// diagnostic.
  364.   // FIXME: Allow shared_ptr keys in DenseMap?
  365.   std::map<PathDiagnosticPieceRef, std::unique_ptr<StackHintGenerator>>
  366.       StackHints;
  367.  
  368. public:
  369.   PathSensitiveBugReport(const BugType &bt, StringRef desc,
  370.                          const ExplodedNode *errorNode)
  371.       : PathSensitiveBugReport(bt, desc, desc, errorNode) {}
  372.  
  373.   PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc,
  374.                          const ExplodedNode *errorNode)
  375.       : PathSensitiveBugReport(bt, shortDesc, desc, errorNode,
  376.                                /*LocationToUnique*/ {},
  377.                                /*DeclToUnique*/ nullptr) {}
  378.  
  379.   /// Create a PathSensitiveBugReport with a custom uniqueing location.
  380.   ///
  381.   /// The reports that have the same report location, description, bug type, and
  382.   /// ranges are uniqued - only one of the equivalent reports will be presented
  383.   /// to the user. This method allows to rest the location which should be used
  384.   /// for uniquing reports. For example, memory leaks checker, could set this to
  385.   /// the allocation site, rather then the location where the bug is reported.
  386.   PathSensitiveBugReport(const BugType &bt, StringRef desc,
  387.                          const ExplodedNode *errorNode,
  388.                          PathDiagnosticLocation LocationToUnique,
  389.                          const Decl *DeclToUnique)
  390.       : PathSensitiveBugReport(bt, desc, desc, errorNode, LocationToUnique,
  391.                                DeclToUnique) {}
  392.  
  393.   PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc,
  394.                          const ExplodedNode *errorNode,
  395.                          PathDiagnosticLocation LocationToUnique,
  396.                          const Decl *DeclToUnique);
  397.  
  398.   static bool classof(const BugReport *R) {
  399.     return R->getKind() == Kind::PathSensitive;
  400.   }
  401.  
  402.   const ExplodedNode *getErrorNode() const { return ErrorNode; }
  403.  
  404.   /// Indicates whether or not any path pruning should take place
  405.   /// when generating a PathDiagnostic from this BugReport.
  406.   bool shouldPrunePath() const { return !DoNotPrunePath; }
  407.  
  408.   /// Disable all path pruning when generating a PathDiagnostic.
  409.   void disablePathPruning() { DoNotPrunePath = true; }
  410.  
  411.   /// Get the location on which the report should be uniqued.
  412.   PathDiagnosticLocation getUniqueingLocation() const override {
  413.     return UniqueingLocation;
  414.   }
  415.  
  416.   /// Get the declaration containing the uniqueing location.
  417.   const Decl *getUniqueingDecl() const override {
  418.     return UniqueingDecl;
  419.   }
  420.  
  421.   const Decl *getDeclWithIssue() const override;
  422.  
  423.   ArrayRef<SourceRange> getRanges() const override;
  424.  
  425.   PathDiagnosticLocation getLocation() const override;
  426.  
  427.   /// Marks a symbol as interesting. Different kinds of interestingness will
  428.   /// be processed differently by visitors (e.g. if the tracking kind is
  429.   /// condition, will append "will be used as a condition" to the message).
  430.   void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind =
  431.                                           bugreporter::TrackingKind::Thorough);
  432.  
  433.   void markNotInteresting(SymbolRef sym);
  434.  
  435.   /// Marks a region as interesting. Different kinds of interestingness will
  436.   /// be processed differently by visitors (e.g. if the tracking kind is
  437.   /// condition, will append "will be used as a condition" to the message).
  438.   void markInteresting(
  439.       const MemRegion *R,
  440.       bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough);
  441.  
  442.   void markNotInteresting(const MemRegion *R);
  443.  
  444.   /// Marks a symbolic value as interesting. Different kinds of interestingness
  445.   /// will be processed differently by visitors (e.g. if the tracking kind is
  446.   /// condition, will append "will be used as a condition" to the message).
  447.   void markInteresting(SVal V, bugreporter::TrackingKind TKind =
  448.                                    bugreporter::TrackingKind::Thorough);
  449.   void markInteresting(const LocationContext *LC);
  450.  
  451.   bool isInteresting(SymbolRef sym) const;
  452.   bool isInteresting(const MemRegion *R) const;
  453.   bool isInteresting(SVal V) const;
  454.   bool isInteresting(const LocationContext *LC) const;
  455.  
  456.   std::optional<bugreporter::TrackingKind>
  457.   getInterestingnessKind(SymbolRef sym) const;
  458.  
  459.   std::optional<bugreporter::TrackingKind>
  460.   getInterestingnessKind(const MemRegion *R) const;
  461.  
  462.   std::optional<bugreporter::TrackingKind> getInterestingnessKind(SVal V) const;
  463.  
  464.   /// Returns whether or not this report should be considered valid.
  465.   ///
  466.   /// Invalid reports are those that have been classified as likely false
  467.   /// positives after the fact.
  468.   bool isValid() const {
  469.     return Invalidations.empty();
  470.   }
  471.  
  472.   /// Marks the current report as invalid, meaning that it is probably a false
  473.   /// positive and should not be reported to the user.
  474.   ///
  475.   /// The \p Tag and \p Data arguments are intended to be opaque identifiers for
  476.   /// this particular invalidation, where \p Tag represents the visitor
  477.   /// responsible for invalidation, and \p Data represents the reason this
  478.   /// visitor decided to invalidate the bug report.
  479.   ///
  480.   /// \sa removeInvalidation
  481.   void markInvalid(const void *Tag, const void *Data) {
  482.     Invalidations.insert(std::make_pair(Tag, Data));
  483.   }
  484.  
  485.   /// Profile to identify equivalent bug reports for error report coalescing.
  486.   /// Reports are uniqued to ensure that we do not emit multiple diagnostics
  487.   /// for each bug.
  488.   void Profile(llvm::FoldingSetNodeID &hash) const override;
  489.  
  490.   /// Add custom or predefined bug report visitors to this report.
  491.   ///
  492.   /// The visitors should be used when the default trace is not sufficient.
  493.   /// For example, they allow constructing a more elaborate trace.
  494.   /// @{
  495.   void addVisitor(std::unique_ptr<BugReporterVisitor> visitor);
  496.  
  497.   template <class VisitorType, class... Args>
  498.   void addVisitor(Args &&... ConstructorArgs) {
  499.     addVisitor(
  500.         std::make_unique<VisitorType>(std::forward<Args>(ConstructorArgs)...));
  501.   }
  502.   /// @}
  503.  
  504.   /// Remove all visitors attached to this bug report.
  505.   void clearVisitors();
  506.  
  507.   /// Iterators through the custom diagnostic visitors.
  508.   visitor_iterator visitor_begin() { return Callbacks.begin(); }
  509.   visitor_iterator visitor_end() { return Callbacks.end(); }
  510.   visitor_range visitors() { return {visitor_begin(), visitor_end()}; }
  511.  
  512.   /// Notes that the condition of the CFGBlock associated with \p Cond is
  513.   /// being tracked.
  514.   /// \returns false if the condition is already being tracked.
  515.   bool addTrackedCondition(const ExplodedNode *Cond) {
  516.     return TrackedConditions.insert(Cond).second;
  517.   }
  518.  
  519.   void addCallStackHint(PathDiagnosticPieceRef Piece,
  520.                         std::unique_ptr<StackHintGenerator> StackHint) {
  521.     StackHints[Piece] = std::move(StackHint);
  522.   }
  523.  
  524.   bool hasCallStackHint(PathDiagnosticPieceRef Piece) const {
  525.     return StackHints.count(Piece) > 0;
  526.   }
  527.  
  528.   /// Produce the hint for the given node. The node contains
  529.   /// information about the call for which the diagnostic can be generated.
  530.   std::string
  531.   getCallStackMessage(PathDiagnosticPieceRef Piece,
  532.                       const ExplodedNode *N) const {
  533.     auto I = StackHints.find(Piece);
  534.     if (I != StackHints.end())
  535.       return I->second->getMessage(N);
  536.     return "";
  537.   }
  538. };
  539.  
  540. //===----------------------------------------------------------------------===//
  541. // BugTypes (collections of related reports).
  542. //===----------------------------------------------------------------------===//
  543.  
  544. class BugReportEquivClass : public llvm::FoldingSetNode {
  545.   friend class BugReporter;
  546.  
  547.   /// List of *owned* BugReport objects.
  548.   llvm::SmallVector<std::unique_ptr<BugReport>, 4> Reports;
  549.  
  550.   void AddReport(std::unique_ptr<BugReport> &&R) {
  551.     Reports.push_back(std::move(R));
  552.   }
  553.  
  554. public:
  555.   BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); }
  556.  
  557.   ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; }
  558.  
  559.   void Profile(llvm::FoldingSetNodeID& ID) const {
  560.     assert(!Reports.empty());
  561.     Reports.front()->Profile(ID);
  562.   }
  563. };
  564.  
  565. //===----------------------------------------------------------------------===//
  566. // BugReporter and friends.
  567. //===----------------------------------------------------------------------===//
  568.  
  569. class BugReporterData {
  570. public:
  571.   virtual ~BugReporterData() = default;
  572.  
  573.   virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0;
  574.   virtual ASTContext &getASTContext() = 0;
  575.   virtual SourceManager &getSourceManager() = 0;
  576.   virtual AnalyzerOptions &getAnalyzerOptions() = 0;
  577.   virtual Preprocessor &getPreprocessor() = 0;
  578. };
  579.  
  580. /// BugReporter is a utility class for generating PathDiagnostics for analysis.
  581. /// It collects the BugReports and BugTypes and knows how to generate
  582. /// and flush the corresponding diagnostics.
  583. ///
  584. /// The base class is used for generating path-insensitive
  585. class BugReporter {
  586. private:
  587.   BugReporterData& D;
  588.  
  589.   /// Generate and flush the diagnostics for the given bug report.
  590.   void FlushReport(BugReportEquivClass& EQ);
  591.  
  592.   /// The set of bug reports tracked by the BugReporter.
  593.   llvm::FoldingSet<BugReportEquivClass> EQClasses;
  594.  
  595.   /// A vector of BugReports for tracking the allocated pointers and cleanup.
  596.   std::vector<BugReportEquivClass *> EQClassesVector;
  597.  
  598. public:
  599.   BugReporter(BugReporterData &d);
  600.   virtual ~BugReporter();
  601.  
  602.   /// Generate and flush diagnostics for all bug reports.
  603.   void FlushReports();
  604.  
  605.   ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() {
  606.     return D.getPathDiagnosticConsumers();
  607.   }
  608.  
  609.   /// Iterator over the set of BugReports tracked by the BugReporter.
  610.   using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator;
  611.   EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
  612.   EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
  613.  
  614.   ASTContext &getContext() { return D.getASTContext(); }
  615.  
  616.   const SourceManager &getSourceManager() { return D.getSourceManager(); }
  617.  
  618.   const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
  619.  
  620.   Preprocessor &getPreprocessor() { return D.getPreprocessor(); }
  621.  
  622.   /// Add the given report to the set of reports tracked by BugReporter.
  623.   ///
  624.   /// The reports are usually generated by the checkers. Further, they are
  625.   /// folded based on the profile value, which is done to coalesce similar
  626.   /// reports.
  627.   virtual void emitReport(std::unique_ptr<BugReport> R);
  628.  
  629.   void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker,
  630.                        StringRef BugName, StringRef BugCategory,
  631.                        StringRef BugStr, PathDiagnosticLocation Loc,
  632.                        ArrayRef<SourceRange> Ranges = std::nullopt,
  633.                        ArrayRef<FixItHint> Fixits = std::nullopt);
  634.  
  635.   void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName,
  636.                        StringRef BugName, StringRef BugCategory,
  637.                        StringRef BugStr, PathDiagnosticLocation Loc,
  638.                        ArrayRef<SourceRange> Ranges = std::nullopt,
  639.                        ArrayRef<FixItHint> Fixits = std::nullopt);
  640.  
  641. private:
  642.   llvm::StringMap<std::unique_ptr<BugType>> StrBugTypes;
  643.  
  644.   /// Returns a BugType that is associated with the given name and
  645.   /// category.
  646.   BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name,
  647.                              StringRef category);
  648.  
  649.   virtual BugReport *
  650.   findReportInEquivalenceClass(BugReportEquivClass &eqClass,
  651.                                SmallVectorImpl<BugReport *> &bugReports) {
  652.     return eqClass.getReports()[0].get();
  653.   }
  654.  
  655. protected:
  656.   /// Generate the diagnostics for the given bug report.
  657.   virtual std::unique_ptr<DiagnosticForConsumerMapTy>
  658.   generateDiagnosticForConsumerMap(BugReport *exampleReport,
  659.                                    ArrayRef<PathDiagnosticConsumer *> consumers,
  660.                                    ArrayRef<BugReport *> bugReports);
  661. };
  662.  
  663. /// GRBugReporter is used for generating path-sensitive reports.
  664. class PathSensitiveBugReporter final : public BugReporter {
  665.   ExprEngine& Eng;
  666.  
  667.   BugReport *findReportInEquivalenceClass(
  668.       BugReportEquivClass &eqClass,
  669.       SmallVectorImpl<BugReport *> &bugReports) override;
  670.  
  671.   /// Generate the diagnostics for the given bug report.
  672.   std::unique_ptr<DiagnosticForConsumerMapTy>
  673.   generateDiagnosticForConsumerMap(BugReport *exampleReport,
  674.                                    ArrayRef<PathDiagnosticConsumer *> consumers,
  675.                                    ArrayRef<BugReport *> bugReports) override;
  676. public:
  677.   PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng)
  678.       : BugReporter(d), Eng(eng) {}
  679.  
  680.   /// getGraph - Get the exploded graph created by the analysis engine
  681.   ///  for the analyzed method or function.
  682.   const ExplodedGraph &getGraph() const;
  683.  
  684.   /// getStateManager - Return the state manager used by the analysis
  685.   ///  engine.
  686.   ProgramStateManager &getStateManager() const;
  687.  
  688.   /// \p bugReports A set of bug reports within a *single* equivalence class
  689.   ///
  690.   /// \return A mapping from consumers to the corresponding diagnostics.
  691.   /// Iterates through the bug reports within a single equivalence class,
  692.   /// stops at a first non-invalidated report.
  693.   std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics(
  694.       ArrayRef<PathDiagnosticConsumer *> consumers,
  695.       ArrayRef<PathSensitiveBugReport *> &bugReports);
  696.  
  697.   void emitReport(std::unique_ptr<BugReport> R) override;
  698. };
  699.  
  700.  
  701. class BugReporterContext {
  702.   PathSensitiveBugReporter &BR;
  703.  
  704.   virtual void anchor();
  705.  
  706. public:
  707.   BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {}
  708.  
  709.   virtual ~BugReporterContext() = default;
  710.  
  711.   PathSensitiveBugReporter& getBugReporter() { return BR; }
  712.  
  713.   ProgramStateManager& getStateManager() const {
  714.     return BR.getStateManager();
  715.   }
  716.  
  717.   ASTContext &getASTContext() const {
  718.     return BR.getContext();
  719.   }
  720.  
  721.   const SourceManager& getSourceManager() const {
  722.     return BR.getSourceManager();
  723.   }
  724.  
  725.   const AnalyzerOptions &getAnalyzerOptions() const {
  726.     return BR.getAnalyzerOptions();
  727.   }
  728. };
  729.  
  730. /// The tag that carries some information with it.
  731. ///
  732. /// It can be valuable to produce tags with some bits of information and later
  733. /// reuse them for a better diagnostic.
  734. ///
  735. /// Please make sure that derived class' constuctor is private and that the user
  736. /// can only create objects using DataTag::Factory.  This also means that
  737. /// DataTag::Factory should be friend for every derived class.
  738. class DataTag : public ProgramPointTag {
  739. public:
  740.   StringRef getTagDescription() const override { return "Data Tag"; }
  741.  
  742.   // Manage memory for DataTag objects.
  743.   class Factory {
  744.     std::vector<std::unique_ptr<DataTag>> Tags;
  745.  
  746.   public:
  747.     template <class DataTagType, class... Args>
  748.     const DataTagType *make(Args &&... ConstructorArgs) {
  749.       // We cannot use std::make_unique because we cannot access the private
  750.       // constructor from inside it.
  751.       Tags.emplace_back(
  752.           new DataTagType(std::forward<Args>(ConstructorArgs)...));
  753.       return static_cast<DataTagType *>(Tags.back().get());
  754.     }
  755.   };
  756.  
  757. protected:
  758.   DataTag(void *TagKind) : ProgramPointTag(TagKind) {}
  759. };
  760.  
  761. /// The tag upon which the TagVisitor reacts. Add these in order to display
  762. /// additional PathDiagnosticEventPieces along the path.
  763. class NoteTag : public DataTag {
  764. public:
  765.   using Callback = std::function<std::string(BugReporterContext &,
  766.                                              PathSensitiveBugReport &)>;
  767.  
  768. private:
  769.   static int Kind;
  770.  
  771.   const Callback Cb;
  772.   const bool IsPrunable;
  773.  
  774.   NoteTag(Callback &&Cb, bool IsPrunable)
  775.       : DataTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {}
  776.  
  777. public:
  778.   static bool classof(const ProgramPointTag *T) {
  779.     return T->getTagKind() == &Kind;
  780.   }
  781.  
  782.   std::optional<std::string> generateMessage(BugReporterContext &BRC,
  783.                                              PathSensitiveBugReport &R) const {
  784.     std::string Msg = Cb(BRC, R);
  785.     if (Msg.empty())
  786.       return std::nullopt;
  787.  
  788.     return std::move(Msg);
  789.   }
  790.  
  791.   StringRef getTagDescription() const override {
  792.     // TODO: Remember a few examples of generated messages
  793.     // and display them in the ExplodedGraph dump by
  794.     // returning them from this function.
  795.     return "Note Tag";
  796.   }
  797.  
  798.   bool isPrunable() const { return IsPrunable; }
  799.  
  800.   friend class Factory;
  801.   friend class TagVisitor;
  802. };
  803.  
  804. } // namespace ento
  805.  
  806. } // namespace clang
  807.  
  808. #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
  809.