1 //===- BugReporterVisitors.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 declares BugReporterVisitors, which are used to generate enhanced
10 //  diagnostic traces.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
15 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
16 
17 #include "clang/Analysis/ProgramPoint.h"
18 #include "clang/Basic/LLVM.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
21 #include "llvm/ADT/FoldingSet.h"
22 #include "llvm/ADT/IntrusiveRefCntPtr.h"
23 #include "llvm/ADT/STLExtras.h"
24 #include "llvm/ADT/SmallPtrSet.h"
25 #include "llvm/ADT/StringRef.h"
26 #include <list>
27 #include <memory>
28 #include <utility>
29 
30 namespace clang {
31 
32 class BinaryOperator;
33 class CFGBlock;
34 class DeclRefExpr;
35 class Expr;
36 class Stmt;
37 
38 namespace ento {
39 
40 class PathSensitiveBugReport;
41 class BugReporterContext;
42 class ExplodedNode;
43 class MemRegion;
44 class PathDiagnosticPiece;
45 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
46 
47 /// BugReporterVisitors are used to add custom diagnostics along a path.
48 class BugReporterVisitor : public llvm::FoldingSetNode {
49 public:
50   BugReporterVisitor() = default;
51   BugReporterVisitor(const BugReporterVisitor &) = default;
52   BugReporterVisitor(BugReporterVisitor &&) {}
53   virtual ~BugReporterVisitor();
54 
55   /// Return a diagnostic piece which should be associated with the
56   /// given node.
57   /// Note that this function does *not* get run on the very last node
58   /// of the report, as the PathDiagnosticPiece associated with the
59   /// last node should be unique.
60   /// Use \ref getEndPath to customize the note associated with the report
61   /// end instead.
62   ///
63   /// The last parameter can be used to register a new visitor with the given
64   /// BugReport while processing a node.
65   virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
66                                            BugReporterContext &BRC,
67                                            PathSensitiveBugReport &BR) = 0;
68 
69   /// Last function called on the visitor, no further calls to VisitNode
70   /// would follow.
71   virtual void finalizeVisitor(BugReporterContext &BRC,
72                                const ExplodedNode *EndPathNode,
73                                PathSensitiveBugReport &BR);
74 
75   /// Provide custom definition for the final diagnostic piece on the
76   /// path - the piece, which is displayed before the path is expanded.
77   ///
78   /// NOTE that this function can be implemented on at most one used visitor,
79   /// and otherwise it crahes at runtime.
80   virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
81                                             const ExplodedNode *N,
82                                             PathSensitiveBugReport &BR);
83 
84   virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
85 
86   /// Generates the default final diagnostic piece.
87   static PathDiagnosticPieceRef
88   getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N,
89                     const PathSensitiveBugReport &BR);
90 };
91 
92 namespace bugreporter {
93 
94 /// Specifies the type of tracking for an expression.
95 enum class TrackingKind {
96   /// Default tracking kind -- specifies that as much information should be
97   /// gathered about the tracked expression value as possible.
98   Thorough,
99   /// Specifies that a more moderate tracking should be used for the expression
100   /// value. This will essentially make sure that functions relevant to it
101   /// aren't pruned, but otherwise relies on the user reading the code or
102   /// following the arrows.
103   Condition
104 };
105 
106 /// Defines a set of options altering tracking behavior.
107 struct TrackingOptions {
108   /// Specifies the kind of tracking.
109   TrackingKind Kind = TrackingKind::Thorough;
110   /// Specifies whether we should employ false positive suppression
111   /// (inlined defensive checks, returned null).
112   bool EnableNullFPSuppression = true;
113 };
114 
115 /// Describes an event when the value got stored into a memory region.
116 ///
117 /// As opposed to checker checkBind API, it reacts also to binds
118 /// generated by the checker as well.  It can be useful when the binding
119 /// happened as a result of evalCall, for example.
120 struct StoreInfo {
121   enum Kind {
122     /// The value got stored into the region during initialization:
123     ///   int x = 42;
124     Initialization,
125     /// The value got stored into the region during assignment:
126     ///   int x;
127     ///   x = 42;
128     Assignment,
129     /// The value got stored into the parameter region as the result
130     /// of a call.
131     CallArgument,
132     /// The value got stored into the region as block capture.
133     /// Block data is modeled as a separate region, thus whenever
134     /// the analyzer sees a captured variable, its value is copied
135     /// into a special block region.
136     BlockCapture
137   };
138 
139   /// The type of store operation.
140   Kind StoreKind;
141   /// The node where the store happened.
142   const ExplodedNode *StoreSite;
143   /// The expression where the value comes from.
144   /// NOTE: might be null.
145   const Expr *SourceOfTheValue;
146   /// Symbolic value that is being stored.
147   SVal Value;
148   /// Memory regions involved in the store operation.
149   ///   Dest <- Origin
150   /// NOTE: Origin might be null, when the stored value doesn't come
151   ///       from another region.
152   const MemRegion *Dest, *Origin;
153 };
154 
155 class Tracker;
156 using TrackerRef = llvm::IntrusiveRefCntPtr<Tracker>;
157 
158 class ExpressionHandler;
159 class StoreHandler;
160 
161 /// A generalized component for tracking expressions, values, and stores.
162 ///
163 /// Tracker aimes at providing a sensible set of default behaviors that can be
164 /// used by any checker, while providing mechanisms to hook into any part of the
165 /// tracking process and insert checker-specific logic.
166 class Tracker : public llvm::RefCountedBase<Tracker> {
167 private:
168   using ExpressionHandlerPtr = std::unique_ptr<ExpressionHandler>;
169   using StoreHandlerPtr = std::unique_ptr<StoreHandler>;
170 
171   PathSensitiveBugReport &Report;
172   std::list<ExpressionHandlerPtr> ExpressionHandlers;
173   std::list<StoreHandlerPtr> StoreHandlers;
174 
175 protected:
176   /// \param Report The bug report to which visitors should be attached.
177   Tracker(PathSensitiveBugReport &Report);
178 
179 public:
180   virtual ~Tracker() = default;
181 
182   static TrackerRef create(PathSensitiveBugReport &Report) {
183     return new Tracker(Report);
184   }
185 
186   PathSensitiveBugReport &getReport() { return Report; }
187 
188   /// Describes a tracking result with the most basic information of what was
189   /// actually done (or not done).
190   struct Result {
191     /// Usually it means that the tracker added visitors.
192     bool FoundSomethingToTrack = false;
193     /// Signifies that the tracking was interrupted at some point.
194     /// Usually this information is important only for sub-trackers.
195     bool WasInterrupted = false;
196 
197     /// Combines the current result with the given result.
198     void combineWith(const Result &Other) {
199       // If we found something in one of the cases, we can
200       // say we found something overall.
201       FoundSomethingToTrack |= Other.FoundSomethingToTrack;
202       // The same goes to the interruption.
203       WasInterrupted |= Other.WasInterrupted;
204     }
205   };
206 
207   /// Track expression value back to its point of origin.
208   ///
209   /// \param E The expression value which we are tracking
210   /// \param N A node "downstream" from the evaluation of the statement.
211   /// \param Opts Tracking options specifying how we want to track the value.
212   virtual Result track(const Expr *E, const ExplodedNode *N,
213                        TrackingOptions Opts = {});
214 
215   /// Track how the value got stored into the given region and where it came
216   /// from.
217   ///
218   /// \param V We're searching for the store where \c R received this value.
219   /// \param R The region we're tracking.
220   /// \param Opts Tracking options specifying how we want to track the value.
221   /// \param Origin Only adds notes when the last store happened in a
222   ///        different stackframe to this one. Disregarded if the tracking kind
223   ///        is thorough.
224   ///        This is useful, because for non-tracked regions, notes about
225   ///        changes to its value in a nested stackframe could be pruned, and
226   ///        this visitor can prevent that without polluting the bugpath too
227   ///        much.
228   virtual Result track(SVal V, const MemRegion *R, TrackingOptions Opts = {},
229                        const StackFrameContext *Origin = nullptr);
230 
231   /// Handle the store operation and produce the note.
232   ///
233   /// \param SI The information fully describing the store.
234   /// \param Opts Tracking options specifying how we got to it.
235   ///
236   /// NOTE: this method is designed for sub-trackers and visitors.
237   virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
238                                         TrackingOptions Opts);
239 
240   /// Add custom expression handler with the highest priority.
241   ///
242   /// It means that it will be asked for handling first, and can prevent
243   /// other handlers from running if decides to interrupt.
244   void addHighPriorityHandler(ExpressionHandlerPtr SH) {
245     ExpressionHandlers.push_front(std::move(SH));
246   }
247 
248   /// Add custom expression handler with the lowest priority.
249   ///
250   /// It means that it will be asked for handling last, and other handlers can
251   /// prevent it from running if any of them decides to interrupt.
252   void addLowPriorityHandler(ExpressionHandlerPtr SH) {
253     ExpressionHandlers.push_back(std::move(SH));
254   }
255 
256   /// Add custom store handler with the highest priority.
257   ///
258   /// It means that it will be asked for handling first, and will prevent
259   /// other handlers from running if it produces non-null note.
260   void addHighPriorityHandler(StoreHandlerPtr SH) {
261     StoreHandlers.push_front(std::move(SH));
262   }
263 
264   /// Add custom store handler with the lowest priority.
265   ///
266   /// It means that it will be asked for handling last, only
267   /// if all other handlers failed to produce the note.
268   void addLowPriorityHandler(StoreHandlerPtr SH) {
269     StoreHandlers.push_back(std::move(SH));
270   }
271 
272   /// Add custom expression/store handler with the highest priority
273   ///
274   /// See other overloads for explanation.
275   template <class HandlerType, class... Args>
276   void addHighPriorityHandler(Args &&... ConstructorArgs) {
277     addHighPriorityHandler(std::make_unique<HandlerType>(
278         *this, std::forward<Args>(ConstructorArgs)...));
279   }
280 
281   /// Add custom expression/store handler with the lowest priority
282   ///
283   /// See other overloads for explanation.
284   template <class HandlerType, class... Args>
285   void addLowPriorityHandler(Args &&... ConstructorArgs) {
286     addLowPriorityHandler(std::make_unique<HandlerType>(
287         *this, std::forward<Args>(ConstructorArgs)...));
288   }
289 };
290 
291 /// Handles expressions during the tracking.
292 class ExpressionHandler {
293 private:
294   Tracker &ParentTracker;
295 
296 public:
297   ExpressionHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
298   virtual ~ExpressionHandler() {}
299 
300   /// Handle the given expression from the given node.
301   ///
302   /// \param E The expression value which we are tracking
303   /// \param Original A node "downstream" where the tracking started.
304   /// \param ExprNode A node where the evaluation of \c E actually happens.
305   /// \param Opts Tracking options specifying how we are tracking the value.
306   virtual Tracker::Result handle(const Expr *E, const ExplodedNode *Original,
307                                  const ExplodedNode *ExprNode,
308                                  TrackingOptions Opts) = 0;
309 
310   /// \Return the tracker that initiated the process.
311   Tracker &getParentTracker() { return ParentTracker; }
312 };
313 
314 /// Handles stores during the tracking.
315 class StoreHandler {
316 private:
317   Tracker &ParentTracker;
318 
319 public:
320   StoreHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
321   virtual ~StoreHandler() {}
322 
323   /// Handle the given store and produce the node.
324   ///
325   /// \param SI The information fully describing the store.
326   /// \param Opts Tracking options specifying how we are tracking the value.
327   ///
328   /// \return the produced note, null if the handler doesn't support this kind
329   ///         of stores.
330   virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
331                                         TrackingOptions Opts) = 0;
332 
333   Tracker &getParentTracker() { return ParentTracker; }
334 
335 protected:
336   PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC,
337                                        StringRef NodeText);
338 };
339 
340 /// Visitor that tracks expressions and values.
341 class TrackingBugReporterVisitor : public BugReporterVisitor {
342 private:
343   TrackerRef ParentTracker;
344 
345 public:
346   TrackingBugReporterVisitor(TrackerRef ParentTracker)
347       : ParentTracker(ParentTracker) {}
348 
349   Tracker &getParentTracker() { return *ParentTracker; }
350 };
351 
352 /// Attempts to add visitors to track expression value back to its point of
353 /// origin.
354 ///
355 /// \param N A node "downstream" from the evaluation of the statement.
356 /// \param E The expression value which we are tracking
357 /// \param R The bug report to which visitors should be attached.
358 /// \param Opts Tracking options specifying how we are tracking the value.
359 ///
360 /// \return Whether or not the function was able to add visitors for this
361 ///         statement. Note that returning \c true does not actually imply
362 ///         that any visitors were added.
363 bool trackExpressionValue(const ExplodedNode *N, const Expr *E,
364                           PathSensitiveBugReport &R, TrackingOptions Opts = {});
365 
366 /// Track how the value got stored into the given region and where it came
367 /// from.
368 ///
369 /// \param V We're searching for the store where \c R received this value.
370 /// \param R The region we're tracking.
371 /// \param Opts Tracking options specifying how we want to track the value.
372 /// \param Origin Only adds notes when the last store happened in a
373 ///        different stackframe to this one. Disregarded if the tracking kind
374 ///        is thorough.
375 ///        This is useful, because for non-tracked regions, notes about
376 ///        changes to its value in a nested stackframe could be pruned, and
377 ///        this visitor can prevent that without polluting the bugpath too
378 ///        much.
379 void trackStoredValue(KnownSVal V, const MemRegion *R,
380                       PathSensitiveBugReport &Report, TrackingOptions Opts = {},
381                       const StackFrameContext *Origin = nullptr);
382 
383 const Expr *getDerefExpr(const Stmt *S);
384 
385 } // namespace bugreporter
386 
387 class TrackConstraintBRVisitor final : public BugReporterVisitor {
388   DefinedSVal Constraint;
389   bool Assumption;
390   bool IsSatisfied = false;
391   bool IsZeroCheck;
392 
393   /// We should start tracking from the last node along the path in which the
394   /// value is constrained.
395   bool IsTrackingTurnedOn = false;
396 
397 public:
398   TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
399       : Constraint(constraint), Assumption(assumption),
400         IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {}
401 
402   void Profile(llvm::FoldingSetNodeID &ID) const override;
403 
404   /// Return the tag associated with this visitor.  This tag will be used
405   /// to make all PathDiagnosticPieces created by this visitor.
406   static const char *getTag();
407 
408   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
409                                    BugReporterContext &BRC,
410                                    PathSensitiveBugReport &BR) override;
411 
412 private:
413   /// Checks if the constraint is valid in the current state.
414   bool isUnderconstrained(const ExplodedNode *N) const;
415 };
416 
417 /// \class NilReceiverBRVisitor
418 /// Prints path notes when a message is sent to a nil receiver.
419 class NilReceiverBRVisitor final : public BugReporterVisitor {
420 public:
421   void Profile(llvm::FoldingSetNodeID &ID) const override {
422     static int x = 0;
423     ID.AddPointer(&x);
424   }
425 
426   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
427                                    BugReporterContext &BRC,
428                                    PathSensitiveBugReport &BR) override;
429 
430   /// If the statement is a message send expression with nil receiver, returns
431   /// the receiver expression. Returns NULL otherwise.
432   static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
433 };
434 
435 /// Visitor that tries to report interesting diagnostics from conditions.
436 class ConditionBRVisitor final : public BugReporterVisitor {
437   // FIXME: constexpr initialization isn't supported by MSVC2013.
438   constexpr static llvm::StringLiteral GenericTrueMessage =
439       "Assuming the condition is true";
440   constexpr static llvm::StringLiteral GenericFalseMessage =
441       "Assuming the condition is false";
442 
443 public:
444   void Profile(llvm::FoldingSetNodeID &ID) const override {
445     static int x = 0;
446     ID.AddPointer(&x);
447   }
448 
449   /// Return the tag associated with this visitor.  This tag will be used
450   /// to make all PathDiagnosticPieces created by this visitor.
451   static const char *getTag();
452 
453   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
454                                    BugReporterContext &BRC,
455                                    PathSensitiveBugReport &BR) override;
456 
457   PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N,
458                                        BugReporterContext &BRC,
459                                        PathSensitiveBugReport &BR);
460 
461   PathDiagnosticPieceRef
462   VisitTerminator(const Stmt *Term, const ExplodedNode *N,
463                   const CFGBlock *SrcBlk, const CFGBlock *DstBlk,
464                   PathSensitiveBugReport &R, BugReporterContext &BRC);
465 
466   PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
467                                        BugReporterContext &BRC,
468                                        PathSensitiveBugReport &R,
469                                        const ExplodedNode *N, bool TookTrue);
470 
471   PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
472                                        BugReporterContext &BRC,
473                                        PathSensitiveBugReport &R,
474                                        const ExplodedNode *N, bool TookTrue,
475                                        bool IsAssuming);
476 
477   PathDiagnosticPieceRef
478   VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
479                 BugReporterContext &BRC, PathSensitiveBugReport &R,
480                 const ExplodedNode *N, bool TookTrue, bool IsAssuming);
481 
482   PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME,
483                                        BugReporterContext &BRC,
484                                        PathSensitiveBugReport &R,
485                                        const ExplodedNode *N, bool TookTrue,
486                                        bool IsAssuming);
487 
488   PathDiagnosticPieceRef
489   VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
490                          BugReporterContext &BRC, PathSensitiveBugReport &R,
491                          const ExplodedNode *N, bool TookTrue);
492 
493   /// Tries to print the value of the given expression.
494   ///
495   /// \param CondVarExpr The expression to print its value.
496   /// \param Out The stream to print.
497   /// \param N The node where we encountered the condition.
498   /// \param TookTrue Whether we took the \c true branch of the condition.
499   ///
500   /// \return Whether the print was successful. (The printing is successful if
501   ///         we model the value and we could obtain it.)
502   bool printValue(const Expr *CondVarExpr, raw_ostream &Out,
503                   const ExplodedNode *N, bool TookTrue, bool IsAssuming);
504 
505   bool patternMatch(const Expr *Ex,
506                     const Expr *ParentEx,
507                     raw_ostream &Out,
508                     BugReporterContext &BRC,
509                     PathSensitiveBugReport &R,
510                     const ExplodedNode *N,
511                     Optional<bool> &prunable,
512                     bool IsSameFieldName);
513 
514   static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
515 };
516 
517 /// Suppress reports that might lead to known false positives.
518 ///
519 /// Currently this suppresses reports based on locations of bugs.
520 class LikelyFalsePositiveSuppressionBRVisitor final
521     : public BugReporterVisitor {
522 public:
523   static void *getTag() {
524     static int Tag = 0;
525     return static_cast<void *>(&Tag);
526   }
527 
528   void Profile(llvm::FoldingSetNodeID &ID) const override {
529     ID.AddPointer(getTag());
530   }
531 
532   PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &,
533                                    PathSensitiveBugReport &) override {
534     return nullptr;
535   }
536 
537   void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
538                        PathSensitiveBugReport &BR) override;
539 };
540 
541 /// When a region containing undefined value or '0' value is passed
542 /// as an argument in a call, marks the call as interesting.
543 ///
544 /// As a result, BugReporter will not prune the path through the function even
545 /// if the region's contents are not modified/accessed by the call.
546 class UndefOrNullArgVisitor final : public BugReporterVisitor {
547   /// The interesting memory region this visitor is tracking.
548   const MemRegion *R;
549 
550 public:
551   UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
552 
553   void Profile(llvm::FoldingSetNodeID &ID) const override {
554     static int Tag = 0;
555     ID.AddPointer(&Tag);
556     ID.AddPointer(R);
557   }
558 
559   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
560                                    BugReporterContext &BRC,
561                                    PathSensitiveBugReport &BR) override;
562 };
563 
564 class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
565   /// The symbolic value for which we are tracking constraints.
566   /// This value is constrained to null in the end of path.
567   DefinedSVal V;
568 
569   /// Track if we found the node where the constraint was first added.
570   bool IsSatisfied = false;
571 
572   /// Since the visitors can be registered on nodes previous to the last
573   /// node in the BugReport, but the path traversal always starts with the last
574   /// node, the visitor invariant (that we start with a node in which V is null)
575   /// might not hold when node visitation starts. We are going to start tracking
576   /// from the last node in which the value is null.
577   bool IsTrackingTurnedOn = false;
578 
579 public:
580   SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
581 
582   void Profile(llvm::FoldingSetNodeID &ID) const override;
583 
584   /// Return the tag associated with this visitor.  This tag will be used
585   /// to make all PathDiagnosticPieces created by this visitor.
586   static const char *getTag();
587 
588   PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
589                                    BugReporterContext &BRC,
590                                    PathSensitiveBugReport &BR) override;
591 };
592 
593 /// The bug visitor will walk all the nodes in a path and collect all the
594 /// constraints. When it reaches the root node, will create a refutation
595 /// manager and check if the constraints are satisfiable
596 class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor {
597 private:
598   /// Holds the constraints in a given path
599   ConstraintMap Constraints;
600 
601 public:
602   FalsePositiveRefutationBRVisitor();
603 
604   void Profile(llvm::FoldingSetNodeID &ID) const override;
605 
606   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
607                                    BugReporterContext &BRC,
608                                    PathSensitiveBugReport &BR) override;
609 
610   void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
611                        PathSensitiveBugReport &BR) override;
612   void addConstraints(const ExplodedNode *N,
613                       bool OverwriteConstraintsOnExistingSyms);
614 };
615 
616 /// The visitor detects NoteTags and displays the event notes they contain.
617 class TagVisitor : public BugReporterVisitor {
618 public:
619   void Profile(llvm::FoldingSetNodeID &ID) const override;
620 
621   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
622                                    BugReporterContext &BRC,
623                                    PathSensitiveBugReport &R) override;
624 };
625 
626 class ObjCMethodCall;
627 class CXXConstructorCall;
628 
629 /// Put a diagnostic on return statement (or on } in its absence) of all inlined
630 /// functions for which some property remained unchanged.
631 /// Resulting diagnostics may read such as "Returning without writing to X".
632 ///
633 /// Descendants can define what a "state change is", like a change of value
634 /// to a memory region, liveness, etc. For function calls where the state did
635 /// not change as defined, a custom note may be constructed.
636 ///
637 /// For a minimal example, check out
638 /// clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp.
639 class NoStateChangeFuncVisitor : public BugReporterVisitor {
640 private:
641   /// Frames modifying the state as defined in \c wasModifiedBeforeCallExit.
642   /// This visitor generates a note only if a function does *not* change the
643   /// state that way. This information is not immediately available
644   /// by looking at the node associated with the exit from the function
645   /// (usually the return statement). To avoid recomputing the same information
646   /// many times (going up the path for each node and checking whether the
647   /// region was written into) we instead lazily compute the stack frames
648   /// along the path.
649   // TODO: Can't we just use a map instead? This is likely not as cheap as it
650   // makes the code difficult to read.
651   llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifying;
652   llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifyingCalculated;
653 
654   /// Check and lazily calculate whether the state is modified in the stack
655   /// frame to which \p CallExitBeginN belongs.
656   /// The calculation is cached in FramesModifying.
657   bool isModifiedInFrame(const ExplodedNode *CallExitBeginN);
658 
659   void markFrameAsModifying(const StackFrameContext *SCtx);
660 
661   /// Write to \c FramesModifying all stack frames along the path in the current
662   /// stack frame which modifies the state.
663   void findModifyingFrames(const ExplodedNode *const CallExitBeginN);
664 
665 protected:
666   bugreporter::TrackingKind TKind;
667 
668   /// \return Whether the state was modified from the current node, \p CurrN, to
669   /// the end of the stack frame, at \p CallExitBeginN. \p CurrN and
670   /// \p CallExitBeginN are always in the same stack frame.
671   /// Clients should override this callback when a state change is important
672   /// not only on the entire function call, but inside of it as well.
673   /// Example: we may want to leave a note about the lack of locking/unlocking
674   /// on a particular mutex, but not if inside the function its state was
675   /// changed, but also restored. wasModifiedInFunction() wouldn't know of this
676   /// change.
677   virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
678                                          const ExplodedNode *CallExitBeginN) {
679     return false;
680   }
681 
682   /// \return Whether the state was modified in the inlined function call in
683   /// between \p CallEnterN and \p CallExitEndN. Mind that the stack frame
684   /// retrieved from a CallEnterN and CallExitEndN is the *caller's* stack
685   /// frame! The inlined function's stack should be retrieved from either the
686   /// immediate successor to \p CallEnterN or immediate predecessor to
687   /// \p CallExitEndN.
688   /// Clients should override this function if a state changes local to the
689   /// inlined function are not interesting, only the change occuring as a
690   /// result of it.
691   /// Example: we want to leave a not about a leaked resource object not being
692   /// deallocated / its ownership changed inside a function, and we don't care
693   /// if it was assigned to a local variable (its change in ownership is
694   /// inconsequential).
695   virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
696                                      const ExplodedNode *CallExitEndN) {
697     return false;
698   }
699 
700   /// Consume the information on the non-modifying stack frame in order to
701   /// either emit a note or not. May suppress the report entirely.
702   /// \return Diagnostics piece for the unmodified state in the current
703   /// function, if it decides to emit one. A good description might start with
704   /// "Returning without...".
705   virtual PathDiagnosticPieceRef
706   maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
707                            const ObjCMethodCall &Call,
708                            const ExplodedNode *N) = 0;
709 
710   /// Consume the information on the non-modifying stack frame in order to
711   /// either emit a note or not. May suppress the report entirely.
712   /// \return Diagnostics piece for the unmodified state in the current
713   /// function, if it decides to emit one. A good description might start with
714   /// "Returning without...".
715   virtual PathDiagnosticPieceRef
716   maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
717                           const CXXConstructorCall &Call,
718                           const ExplodedNode *N) = 0;
719 
720   /// Consume the information on the non-modifying stack frame in order to
721   /// either emit a note or not. May suppress the report entirely.
722   /// \return Diagnostics piece for the unmodified state in the current
723   /// function, if it decides to emit one. A good description might start with
724   /// "Returning without...".
725   virtual PathDiagnosticPieceRef
726   maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
727                              const ExplodedNode *N) = 0;
728 
729 public:
730   NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind) : TKind(TKind) {}
731 
732   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
733                                    BugReporterContext &BR,
734                                    PathSensitiveBugReport &R) override final;
735 };
736 
737 } // namespace ento
738 } // namespace clang
739 
740 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
741