Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:37:07

0001 //===- BugReporterVisitors.h - Generate PathDiagnostics ---------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file declares BugReporterVisitors, which are used to generate enhanced
0010 //  diagnostic traces.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
0015 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
0016 
0017 #include "clang/Analysis/ProgramPoint.h"
0018 #include "clang/Basic/LLVM.h"
0019 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
0020 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
0021 #include "llvm/ADT/FoldingSet.h"
0022 #include "llvm/ADT/IntrusiveRefCntPtr.h"
0023 #include "llvm/ADT/STLExtras.h"
0024 #include "llvm/ADT/SmallPtrSet.h"
0025 #include "llvm/ADT/StringRef.h"
0026 #include <list>
0027 #include <memory>
0028 #include <optional>
0029 #include <utility>
0030 
0031 namespace clang {
0032 
0033 class BinaryOperator;
0034 class CFGBlock;
0035 class DeclRefExpr;
0036 class Expr;
0037 class Stmt;
0038 
0039 namespace ento {
0040 
0041 class PathSensitiveBugReport;
0042 class BugReporterContext;
0043 class ExplodedNode;
0044 class MemRegion;
0045 class PathDiagnosticPiece;
0046 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
0047 
0048 /// BugReporterVisitors are used to add custom diagnostics along a path.
0049 class BugReporterVisitor : public llvm::FoldingSetNode {
0050 public:
0051   BugReporterVisitor() = default;
0052   BugReporterVisitor(const BugReporterVisitor &) = default;
0053   BugReporterVisitor(BugReporterVisitor &&) {}
0054 
0055   // The copy and move assignment operator is defined as deleted pending further
0056   // motivation.
0057   BugReporterVisitor &operator=(const BugReporterVisitor &) = delete;
0058   BugReporterVisitor &operator=(BugReporterVisitor &&) = delete;
0059 
0060   virtual ~BugReporterVisitor();
0061 
0062   /// Return a diagnostic piece which should be associated with the
0063   /// given node.
0064   /// Note that this function does *not* get run on the very last node
0065   /// of the report, as the PathDiagnosticPiece associated with the
0066   /// last node should be unique.
0067   /// Use \ref getEndPath to customize the note associated with the report
0068   /// end instead.
0069   ///
0070   /// The last parameter can be used to register a new visitor with the given
0071   /// BugReport while processing a node.
0072   virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
0073                                            BugReporterContext &BRC,
0074                                            PathSensitiveBugReport &BR) = 0;
0075 
0076   /// Last function called on the visitor, no further calls to VisitNode
0077   /// would follow.
0078   virtual void finalizeVisitor(BugReporterContext &BRC,
0079                                const ExplodedNode *EndPathNode,
0080                                PathSensitiveBugReport &BR);
0081 
0082   /// Provide custom definition for the final diagnostic piece on the
0083   /// path - the piece, which is displayed before the path is expanded.
0084   ///
0085   /// NOTE that this function can be implemented on at most one used visitor,
0086   /// and otherwise it crahes at runtime.
0087   virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
0088                                             const ExplodedNode *N,
0089                                             PathSensitiveBugReport &BR);
0090 
0091   virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
0092 
0093   /// Generates the default final diagnostic piece.
0094   static PathDiagnosticPieceRef
0095   getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N,
0096                     const PathSensitiveBugReport &BR);
0097 };
0098 
0099 namespace bugreporter {
0100 
0101 /// Specifies the type of tracking for an expression.
0102 enum class TrackingKind {
0103   /// Default tracking kind -- specifies that as much information should be
0104   /// gathered about the tracked expression value as possible.
0105   Thorough,
0106   /// Specifies that a more moderate tracking should be used for the expression
0107   /// value. This will essentially make sure that functions relevant to it
0108   /// aren't pruned, but otherwise relies on the user reading the code or
0109   /// following the arrows.
0110   Condition
0111 };
0112 
0113 /// Defines a set of options altering tracking behavior.
0114 struct TrackingOptions {
0115   /// Specifies the kind of tracking.
0116   TrackingKind Kind = TrackingKind::Thorough;
0117   /// Specifies whether we should employ false positive suppression
0118   /// (inlined defensive checks, returned null).
0119   bool EnableNullFPSuppression = true;
0120 };
0121 
0122 /// Describes an event when the value got stored into a memory region.
0123 ///
0124 /// As opposed to checker checkBind API, it reacts also to binds
0125 /// generated by the checker as well.  It can be useful when the binding
0126 /// happened as a result of evalCall, for example.
0127 struct StoreInfo {
0128   enum Kind {
0129     /// The value got stored into the region during initialization:
0130     ///   int x = 42;
0131     Initialization,
0132     /// The value got stored into the region during assignment:
0133     ///   int x;
0134     ///   x = 42;
0135     Assignment,
0136     /// The value got stored into the parameter region as the result
0137     /// of a call.
0138     CallArgument,
0139     /// The value got stored into the region as block capture.
0140     /// Block data is modeled as a separate region, thus whenever
0141     /// the analyzer sees a captured variable, its value is copied
0142     /// into a special block region.
0143     BlockCapture
0144   };
0145 
0146   /// The type of store operation.
0147   Kind StoreKind;
0148   /// The node where the store happened.
0149   const ExplodedNode *StoreSite;
0150   /// The expression where the value comes from.
0151   /// NOTE: might be null.
0152   const Expr *SourceOfTheValue;
0153   /// Symbolic value that is being stored.
0154   SVal Value;
0155   /// Memory regions involved in the store operation.
0156   ///   Dest <- Origin
0157   /// NOTE: Origin might be null, when the stored value doesn't come
0158   ///       from another region.
0159   const MemRegion *Dest, *Origin;
0160 };
0161 
0162 class Tracker;
0163 using TrackerRef = llvm::IntrusiveRefCntPtr<Tracker>;
0164 
0165 class ExpressionHandler;
0166 class StoreHandler;
0167 
0168 /// A generalized component for tracking expressions, values, and stores.
0169 ///
0170 /// Tracker aimes at providing a sensible set of default behaviors that can be
0171 /// used by any checker, while providing mechanisms to hook into any part of the
0172 /// tracking process and insert checker-specific logic.
0173 class Tracker : public llvm::RefCountedBase<Tracker> {
0174 private:
0175   using ExpressionHandlerPtr = std::unique_ptr<ExpressionHandler>;
0176   using StoreHandlerPtr = std::unique_ptr<StoreHandler>;
0177 
0178   PathSensitiveBugReport &Report;
0179   std::list<ExpressionHandlerPtr> ExpressionHandlers;
0180   std::list<StoreHandlerPtr> StoreHandlers;
0181 
0182 protected:
0183   /// \param Report The bug report to which visitors should be attached.
0184   Tracker(PathSensitiveBugReport &Report);
0185 
0186 public:
0187   virtual ~Tracker() = default;
0188 
0189   static TrackerRef create(PathSensitiveBugReport &Report) {
0190     return new Tracker(Report);
0191   }
0192 
0193   PathSensitiveBugReport &getReport() { return Report; }
0194 
0195   /// Describes a tracking result with the most basic information of what was
0196   /// actually done (or not done).
0197   struct Result {
0198     /// Usually it means that the tracker added visitors.
0199     bool FoundSomethingToTrack = false;
0200     /// Signifies that the tracking was interrupted at some point.
0201     /// Usually this information is important only for sub-trackers.
0202     bool WasInterrupted = false;
0203 
0204     /// Combines the current result with the given result.
0205     void combineWith(const Result &Other) {
0206       // If we found something in one of the cases, we can
0207       // say we found something overall.
0208       FoundSomethingToTrack |= Other.FoundSomethingToTrack;
0209       // The same goes to the interruption.
0210       WasInterrupted |= Other.WasInterrupted;
0211     }
0212   };
0213 
0214   /// Track expression value back to its point of origin.
0215   ///
0216   /// \param E The expression value which we are tracking
0217   /// \param N A node "downstream" from the evaluation of the statement.
0218   /// \param Opts Tracking options specifying how we want to track the value.
0219   virtual Result track(const Expr *E, const ExplodedNode *N,
0220                        TrackingOptions Opts = {});
0221 
0222   /// Track how the value got stored into the given region and where it came
0223   /// from.
0224   ///
0225   /// \param V We're searching for the store where \c R received this value.
0226   /// \param R The region we're tracking.
0227   /// \param Opts Tracking options specifying how we want to track the value.
0228   /// \param Origin Only adds notes when the last store happened in a
0229   ///        different stackframe to this one. Disregarded if the tracking kind
0230   ///        is thorough.
0231   ///        This is useful, because for non-tracked regions, notes about
0232   ///        changes to its value in a nested stackframe could be pruned, and
0233   ///        this visitor can prevent that without polluting the bugpath too
0234   ///        much.
0235   virtual Result track(SVal V, const MemRegion *R, TrackingOptions Opts = {},
0236                        const StackFrameContext *Origin = nullptr);
0237 
0238   /// Handle the store operation and produce the note.
0239   ///
0240   /// \param SI The information fully describing the store.
0241   /// \param Opts Tracking options specifying how we got to it.
0242   ///
0243   /// NOTE: this method is designed for sub-trackers and visitors.
0244   virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
0245                                         TrackingOptions Opts);
0246 
0247   /// Add custom expression handler with the highest priority.
0248   ///
0249   /// It means that it will be asked for handling first, and can prevent
0250   /// other handlers from running if decides to interrupt.
0251   void addHighPriorityHandler(ExpressionHandlerPtr SH) {
0252     ExpressionHandlers.push_front(std::move(SH));
0253   }
0254 
0255   /// Add custom expression handler with the lowest priority.
0256   ///
0257   /// It means that it will be asked for handling last, and other handlers can
0258   /// prevent it from running if any of them decides to interrupt.
0259   void addLowPriorityHandler(ExpressionHandlerPtr SH) {
0260     ExpressionHandlers.push_back(std::move(SH));
0261   }
0262 
0263   /// Add custom store handler with the highest priority.
0264   ///
0265   /// It means that it will be asked for handling first, and will prevent
0266   /// other handlers from running if it produces non-null note.
0267   void addHighPriorityHandler(StoreHandlerPtr SH) {
0268     StoreHandlers.push_front(std::move(SH));
0269   }
0270 
0271   /// Add custom store handler with the lowest priority.
0272   ///
0273   /// It means that it will be asked for handling last, only
0274   /// if all other handlers failed to produce the note.
0275   void addLowPriorityHandler(StoreHandlerPtr SH) {
0276     StoreHandlers.push_back(std::move(SH));
0277   }
0278 
0279   /// Add custom expression/store handler with the highest priority
0280   ///
0281   /// See other overloads for explanation.
0282   template <class HandlerType, class... Args>
0283   void addHighPriorityHandler(Args &&... ConstructorArgs) {
0284     addHighPriorityHandler(std::make_unique<HandlerType>(
0285         *this, std::forward<Args>(ConstructorArgs)...));
0286   }
0287 
0288   /// Add custom expression/store handler with the lowest priority
0289   ///
0290   /// See other overloads for explanation.
0291   template <class HandlerType, class... Args>
0292   void addLowPriorityHandler(Args &&... ConstructorArgs) {
0293     addLowPriorityHandler(std::make_unique<HandlerType>(
0294         *this, std::forward<Args>(ConstructorArgs)...));
0295   }
0296 };
0297 
0298 /// Handles expressions during the tracking.
0299 class ExpressionHandler {
0300 private:
0301   Tracker &ParentTracker;
0302 
0303 public:
0304   ExpressionHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
0305   virtual ~ExpressionHandler() {}
0306 
0307   /// Handle the given expression from the given node.
0308   ///
0309   /// \param E The expression value which we are tracking
0310   /// \param Original A node "downstream" where the tracking started.
0311   /// \param ExprNode A node where the evaluation of \c E actually happens.
0312   /// \param Opts Tracking options specifying how we are tracking the value.
0313   virtual Tracker::Result handle(const Expr *E, const ExplodedNode *Original,
0314                                  const ExplodedNode *ExprNode,
0315                                  TrackingOptions Opts) = 0;
0316 
0317   /// \Return the tracker that initiated the process.
0318   Tracker &getParentTracker() { return ParentTracker; }
0319 };
0320 
0321 /// Handles stores during the tracking.
0322 class StoreHandler {
0323 private:
0324   Tracker &ParentTracker;
0325 
0326 public:
0327   StoreHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
0328   virtual ~StoreHandler() {}
0329 
0330   /// Handle the given store and produce the node.
0331   ///
0332   /// \param SI The information fully describing the store.
0333   /// \param Opts Tracking options specifying how we are tracking the value.
0334   ///
0335   /// \return the produced note, null if the handler doesn't support this kind
0336   ///         of stores.
0337   virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
0338                                         TrackingOptions Opts) = 0;
0339 
0340   Tracker &getParentTracker() { return ParentTracker; }
0341 
0342 protected:
0343   PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC,
0344                                        StringRef NodeText);
0345 };
0346 
0347 /// Visitor that tracks expressions and values.
0348 class TrackingBugReporterVisitor : public BugReporterVisitor {
0349 private:
0350   TrackerRef ParentTracker;
0351 
0352 public:
0353   TrackingBugReporterVisitor(TrackerRef ParentTracker)
0354       : ParentTracker(ParentTracker) {}
0355 
0356   Tracker &getParentTracker() { return *ParentTracker; }
0357 };
0358 
0359 /// Attempts to add visitors to track expression value back to its point of
0360 /// origin.
0361 ///
0362 /// \param N A node "downstream" from the evaluation of the statement.
0363 /// \param E The expression value which we are tracking
0364 /// \param R The bug report to which visitors should be attached.
0365 /// \param Opts Tracking options specifying how we are tracking the value.
0366 ///
0367 /// \return Whether or not the function was able to add visitors for this
0368 ///         statement. Note that returning \c true does not actually imply
0369 ///         that any visitors were added.
0370 bool trackExpressionValue(const ExplodedNode *N, const Expr *E,
0371                           PathSensitiveBugReport &R, TrackingOptions Opts = {});
0372 
0373 /// Track how the value got stored into the given region and where it came
0374 /// from.
0375 ///
0376 /// \param V We're searching for the store where \c R received this value.
0377 ///        It may be either defined or undefined, but should not be unknown.
0378 /// \param R The region we're tracking.
0379 /// \param Opts Tracking options specifying how we want to track the value.
0380 /// \param Origin Only adds notes when the last store happened in a
0381 ///        different stackframe to this one. Disregarded if the tracking kind
0382 ///        is thorough.
0383 ///        This is useful, because for non-tracked regions, notes about
0384 ///        changes to its value in a nested stackframe could be pruned, and
0385 ///        this visitor can prevent that without polluting the bugpath too
0386 ///        much.
0387 void trackStoredValue(SVal V, const MemRegion *R,
0388                       PathSensitiveBugReport &Report, TrackingOptions Opts = {},
0389                       const StackFrameContext *Origin = nullptr);
0390 
0391 const Expr *getDerefExpr(const Stmt *S);
0392 
0393 } // namespace bugreporter
0394 
0395 class TrackConstraintBRVisitor final : public BugReporterVisitor {
0396   const SmallString<64> Message;
0397   const DefinedSVal Constraint;
0398   const bool Assumption;
0399   bool IsSatisfied = false;
0400 
0401   /// We should start tracking from the last node along the path in which the
0402   /// value is constrained.
0403   bool IsTrackingTurnedOn = false;
0404 
0405 public:
0406   TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption,
0407                            StringRef Message)
0408       : Message(Message), Constraint(constraint), Assumption(assumption) {}
0409 
0410   void Profile(llvm::FoldingSetNodeID &ID) const override;
0411 
0412   /// Return the tag associated with this visitor.  This tag will be used
0413   /// to make all PathDiagnosticPieces created by this visitor.
0414   static const char *getTag();
0415 
0416   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0417                                    BugReporterContext &BRC,
0418                                    PathSensitiveBugReport &BR) override;
0419 
0420 private:
0421   /// Checks if the constraint refers to a null-location.
0422   bool isZeroCheck() const;
0423 
0424   /// Checks if the constraint is valid in the current state.
0425   bool isUnderconstrained(const ExplodedNode *N) const;
0426 };
0427 
0428 /// \class NilReceiverBRVisitor
0429 /// Prints path notes when a message is sent to a nil receiver.
0430 class NilReceiverBRVisitor final : public BugReporterVisitor {
0431 public:
0432   void Profile(llvm::FoldingSetNodeID &ID) const override {
0433     static int x = 0;
0434     ID.AddPointer(&x);
0435   }
0436 
0437   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0438                                    BugReporterContext &BRC,
0439                                    PathSensitiveBugReport &BR) override;
0440 
0441   /// If the statement is a message send expression with nil receiver, returns
0442   /// the receiver expression. Returns NULL otherwise.
0443   static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
0444 };
0445 
0446 /// Visitor that tries to report interesting diagnostics from conditions.
0447 class ConditionBRVisitor final : public BugReporterVisitor {
0448   // FIXME: constexpr initialization isn't supported by MSVC2013.
0449   constexpr static llvm::StringLiteral GenericTrueMessage =
0450       "Assuming the condition is true";
0451   constexpr static llvm::StringLiteral GenericFalseMessage =
0452       "Assuming the condition is false";
0453 
0454 public:
0455   void Profile(llvm::FoldingSetNodeID &ID) const override {
0456     static int x = 0;
0457     ID.AddPointer(&x);
0458   }
0459 
0460   /// Return the tag associated with this visitor.  This tag will be used
0461   /// to make all PathDiagnosticPieces created by this visitor.
0462   static const char *getTag();
0463 
0464   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0465                                    BugReporterContext &BRC,
0466                                    PathSensitiveBugReport &BR) override;
0467 
0468   PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N,
0469                                        BugReporterContext &BRC,
0470                                        PathSensitiveBugReport &BR);
0471 
0472   PathDiagnosticPieceRef
0473   VisitTerminator(const Stmt *Term, const ExplodedNode *N,
0474                   const CFGBlock *SrcBlk, const CFGBlock *DstBlk,
0475                   PathSensitiveBugReport &R, BugReporterContext &BRC);
0476 
0477   PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
0478                                        BugReporterContext &BRC,
0479                                        PathSensitiveBugReport &R,
0480                                        const ExplodedNode *N, bool TookTrue);
0481 
0482   PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
0483                                        BugReporterContext &BRC,
0484                                        PathSensitiveBugReport &R,
0485                                        const ExplodedNode *N, bool TookTrue,
0486                                        bool IsAssuming);
0487 
0488   PathDiagnosticPieceRef
0489   VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
0490                 BugReporterContext &BRC, PathSensitiveBugReport &R,
0491                 const ExplodedNode *N, bool TookTrue, bool IsAssuming);
0492 
0493   PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME,
0494                                        BugReporterContext &BRC,
0495                                        PathSensitiveBugReport &R,
0496                                        const ExplodedNode *N, bool TookTrue,
0497                                        bool IsAssuming);
0498 
0499   PathDiagnosticPieceRef
0500   VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
0501                          BugReporterContext &BRC, PathSensitiveBugReport &R,
0502                          const ExplodedNode *N, bool TookTrue);
0503 
0504   /// Tries to print the value of the given expression.
0505   ///
0506   /// \param CondVarExpr The expression to print its value.
0507   /// \param Out The stream to print.
0508   /// \param N The node where we encountered the condition.
0509   /// \param TookTrue Whether we took the \c true branch of the condition.
0510   ///
0511   /// \return Whether the print was successful. (The printing is successful if
0512   ///         we model the value and we could obtain it.)
0513   bool printValue(const Expr *CondVarExpr, raw_ostream &Out,
0514                   const ExplodedNode *N, bool TookTrue, bool IsAssuming);
0515 
0516   bool patternMatch(const Expr *Ex, const Expr *ParentEx, raw_ostream &Out,
0517                     BugReporterContext &BRC, PathSensitiveBugReport &R,
0518                     const ExplodedNode *N, std::optional<bool> &prunable,
0519                     bool IsSameFieldName);
0520 
0521   static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
0522 };
0523 
0524 /// Suppress reports that might lead to known false positives.
0525 ///
0526 /// Currently this suppresses reports based on locations of bugs.
0527 class LikelyFalsePositiveSuppressionBRVisitor final
0528     : public BugReporterVisitor {
0529 public:
0530   static void *getTag() {
0531     static int Tag = 0;
0532     return static_cast<void *>(&Tag);
0533   }
0534 
0535   void Profile(llvm::FoldingSetNodeID &ID) const override {
0536     ID.AddPointer(getTag());
0537   }
0538 
0539   PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &,
0540                                    PathSensitiveBugReport &) override {
0541     return nullptr;
0542   }
0543 
0544   void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
0545                        PathSensitiveBugReport &BR) override;
0546 };
0547 
0548 /// When a region containing undefined value or '0' value is passed
0549 /// as an argument in a call, marks the call as interesting.
0550 ///
0551 /// As a result, BugReporter will not prune the path through the function even
0552 /// if the region's contents are not modified/accessed by the call.
0553 class UndefOrNullArgVisitor final : public BugReporterVisitor {
0554   /// The interesting memory region this visitor is tracking.
0555   const MemRegion *R;
0556 
0557 public:
0558   UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
0559 
0560   void Profile(llvm::FoldingSetNodeID &ID) const override {
0561     static int Tag = 0;
0562     ID.AddPointer(&Tag);
0563     ID.AddPointer(R);
0564   }
0565 
0566   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0567                                    BugReporterContext &BRC,
0568                                    PathSensitiveBugReport &BR) override;
0569 };
0570 
0571 class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
0572   /// The symbolic value for which we are tracking constraints.
0573   /// This value is constrained to null in the end of path.
0574   DefinedSVal V;
0575 
0576   /// Track if we found the node where the constraint was first added.
0577   bool IsSatisfied = false;
0578 
0579   /// Since the visitors can be registered on nodes previous to the last
0580   /// node in the BugReport, but the path traversal always starts with the last
0581   /// node, the visitor invariant (that we start with a node in which V is null)
0582   /// might not hold when node visitation starts. We are going to start tracking
0583   /// from the last node in which the value is null.
0584   bool IsTrackingTurnedOn = false;
0585 
0586 public:
0587   SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
0588 
0589   void Profile(llvm::FoldingSetNodeID &ID) const override;
0590 
0591   /// Return the tag associated with this visitor.  This tag will be used
0592   /// to make all PathDiagnosticPieces created by this visitor.
0593   static const char *getTag();
0594 
0595   PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
0596                                    BugReporterContext &BRC,
0597                                    PathSensitiveBugReport &BR) override;
0598 };
0599 
0600 /// The visitor detects NoteTags and displays the event notes they contain.
0601 class TagVisitor : public BugReporterVisitor {
0602 public:
0603   void Profile(llvm::FoldingSetNodeID &ID) const override;
0604 
0605   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0606                                    BugReporterContext &BRC,
0607                                    PathSensitiveBugReport &R) override;
0608 };
0609 
0610 class ObjCMethodCall;
0611 class CXXConstructorCall;
0612 
0613 /// Put a diagnostic on return statement (or on } in its absence) of all inlined
0614 /// functions for which some property remained unchanged.
0615 /// Resulting diagnostics may read such as "Returning without writing to X".
0616 ///
0617 /// Descendants can define what a "state change is", like a change of value
0618 /// to a memory region, liveness, etc. For function calls where the state did
0619 /// not change as defined, a custom note may be constructed.
0620 ///
0621 /// For a minimal example, check out
0622 /// clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp.
0623 class NoStateChangeFuncVisitor : public BugReporterVisitor {
0624 private:
0625   /// Frames modifying the state as defined in \c wasModifiedBeforeCallExit.
0626   /// This visitor generates a note only if a function does *not* change the
0627   /// state that way. This information is not immediately available
0628   /// by looking at the node associated with the exit from the function
0629   /// (usually the return statement). To avoid recomputing the same information
0630   /// many times (going up the path for each node and checking whether the
0631   /// region was written into) we instead lazily compute the stack frames
0632   /// along the path.
0633   // TODO: Can't we just use a map instead? This is likely not as cheap as it
0634   // makes the code difficult to read.
0635   llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifying;
0636   llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifyingCalculated;
0637 
0638   /// Check and lazily calculate whether the state is modified in the stack
0639   /// frame to which \p CallExitBeginN belongs.
0640   /// The calculation is cached in FramesModifying.
0641   bool isModifiedInFrame(const ExplodedNode *CallExitBeginN);
0642 
0643   void markFrameAsModifying(const StackFrameContext *SCtx);
0644 
0645   /// Write to \c FramesModifying all stack frames along the path in the current
0646   /// stack frame which modifies the state.
0647   void findModifyingFrames(const ExplodedNode *const CallExitBeginN);
0648 
0649 protected:
0650   bugreporter::TrackingKind TKind;
0651 
0652   /// \return Whether the state was modified from the current node, \p CurrN, to
0653   /// the end of the stack frame, at \p CallExitBeginN. \p CurrN and
0654   /// \p CallExitBeginN are always in the same stack frame.
0655   /// Clients should override this callback when a state change is important
0656   /// not only on the entire function call, but inside of it as well.
0657   /// Example: we may want to leave a note about the lack of locking/unlocking
0658   /// on a particular mutex, but not if inside the function its state was
0659   /// changed, but also restored. wasModifiedInFunction() wouldn't know of this
0660   /// change.
0661   virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
0662                                          const ExplodedNode *CallExitBeginN) {
0663     return false;
0664   }
0665 
0666   /// \return Whether the state was modified in the inlined function call in
0667   /// between \p CallEnterN and \p CallExitEndN. Mind that the stack frame
0668   /// retrieved from a CallEnterN and CallExitEndN is the *caller's* stack
0669   /// frame! The inlined function's stack should be retrieved from either the
0670   /// immediate successor to \p CallEnterN or immediate predecessor to
0671   /// \p CallExitEndN.
0672   /// Clients should override this function if a state changes local to the
0673   /// inlined function are not interesting, only the change occuring as a
0674   /// result of it.
0675   /// Example: we want to leave a not about a leaked resource object not being
0676   /// deallocated / its ownership changed inside a function, and we don't care
0677   /// if it was assigned to a local variable (its change in ownership is
0678   /// inconsequential).
0679   virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
0680                                      const ExplodedNode *CallExitEndN) {
0681     return false;
0682   }
0683 
0684   /// Consume the information on the non-modifying stack frame in order to
0685   /// either emit a note or not. May suppress the report entirely.
0686   /// \return Diagnostics piece for the unmodified state in the current
0687   /// function, if it decides to emit one. A good description might start with
0688   /// "Returning without...".
0689   virtual PathDiagnosticPieceRef
0690   maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
0691                            const ObjCMethodCall &Call,
0692                            const ExplodedNode *N) = 0;
0693 
0694   /// Consume the information on the non-modifying stack frame in order to
0695   /// either emit a note or not. May suppress the report entirely.
0696   /// \return Diagnostics piece for the unmodified state in the current
0697   /// function, if it decides to emit one. A good description might start with
0698   /// "Returning without...".
0699   virtual PathDiagnosticPieceRef
0700   maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
0701                           const CXXConstructorCall &Call,
0702                           const ExplodedNode *N) = 0;
0703 
0704   /// Consume the information on the non-modifying stack frame in order to
0705   /// either emit a note or not. May suppress the report entirely.
0706   /// \return Diagnostics piece for the unmodified state in the current
0707   /// function, if it decides to emit one. A good description might start with
0708   /// "Returning without...".
0709   virtual PathDiagnosticPieceRef
0710   maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
0711                              const ExplodedNode *N) = 0;
0712 
0713 public:
0714   NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind) : TKind(TKind) {}
0715 
0716   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0717                                    BugReporterContext &BR,
0718                                    PathSensitiveBugReport &R) final;
0719 };
0720 
0721 /// Put a diagnostic on return statement of all inlined functions
0722 /// for which  the region of interest \p RegionOfInterest was passed into,
0723 /// but not written inside, and it has caused an undefined read or a null
0724 /// pointer dereference outside.
0725 class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor {
0726   const SubRegion *RegionOfInterest;
0727   MemRegionManager &MmrMgr;
0728   const SourceManager &SM;
0729   const PrintingPolicy &PP;
0730 
0731   /// Recursion limit for dereferencing fields when looking for the
0732   /// region of interest.
0733   /// The limit of two indicates that we will dereference fields only once.
0734   static const unsigned DEREFERENCE_LIMIT = 2;
0735 
0736   using RegionVector = SmallVector<const MemRegion *, 5>;
0737 
0738 public:
0739   NoStoreFuncVisitor(
0740       const SubRegion *R,
0741       bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough)
0742       : NoStateChangeFuncVisitor(TKind), RegionOfInterest(R),
0743         MmrMgr(R->getMemRegionManager()),
0744         SM(MmrMgr.getContext().getSourceManager()),
0745         PP(MmrMgr.getContext().getPrintingPolicy()) {}
0746 
0747   void Profile(llvm::FoldingSetNodeID &ID) const override {
0748     static int Tag = 0;
0749     ID.AddPointer(&Tag);
0750     ID.AddPointer(RegionOfInterest);
0751   }
0752 
0753 private:
0754   /// \return Whether \c RegionOfInterest was modified at \p CurrN compared to
0755   /// the value it holds in \p CallExitBeginN.
0756   bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
0757                                  const ExplodedNode *CallExitBeginN) override;
0758 
0759   /// Attempts to find the region of interest in a given record decl,
0760   /// by either following the base classes or fields.
0761   /// Dereferences fields up to a given recursion limit.
0762   /// Note that \p Vec is passed by value, leading to quadratic copying cost,
0763   /// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
0764   /// \return A chain fields leading to the region of interest or std::nullopt.
0765   const std::optional<RegionVector>
0766   findRegionOfInterestInRecord(const RecordDecl *RD, ProgramStateRef State,
0767                                const MemRegion *R, const RegionVector &Vec = {},
0768                                int depth = 0);
0769 
0770   // Region of interest corresponds to an IVar, exiting a method
0771   // which could have written into that IVar, but did not.
0772   PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
0773                                                   const ObjCMethodCall &Call,
0774                                                   const ExplodedNode *N) final;
0775 
0776   PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
0777                                                  const CXXConstructorCall &Call,
0778                                                  const ExplodedNode *N) final;
0779 
0780   PathDiagnosticPieceRef
0781   maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
0782                              const ExplodedNode *N) final;
0783 
0784   /// Consume the information on the no-store stack frame in order to
0785   /// either emit a note or suppress the report entirely.
0786   /// \return Diagnostics piece for region not modified in the current function,
0787   /// if it decides to emit one.
0788   PathDiagnosticPieceRef
0789   maybeEmitNote(PathSensitiveBugReport &R, const CallEvent &Call,
0790                 const ExplodedNode *N, const RegionVector &FieldChain,
0791                 const MemRegion *MatchedRegion, StringRef FirstElement,
0792                 bool FirstIsReferenceType, unsigned IndirectionLevel);
0793 
0794   bool prettyPrintRegionName(const RegionVector &FieldChain,
0795                              const MemRegion *MatchedRegion,
0796                              StringRef FirstElement, bool FirstIsReferenceType,
0797                              unsigned IndirectionLevel,
0798                              llvm::raw_svector_ostream &os);
0799 
0800   StringRef prettyPrintFirstElement(StringRef FirstElement,
0801                                     bool MoreItemsExpected,
0802                                     int IndirectionLevel,
0803                                     llvm::raw_svector_ostream &os);
0804 };
0805 
0806 } // namespace ento
0807 } // namespace clang
0808 
0809 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H