diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h @@ -85,6 +85,26 @@ const PathSensitiveBugReport &BR); }; +/// StoppableBugReporterVisitor is a special type of visitor that is known to +/// not have any useful work to do after it reaches a certain node in its +/// traversal. When it does reach that node, the \ref Stop method must be +/// called. This in turn calls the \ref OnStop method (which must be overriden +/// in the sub-class). Note that such visitors *must* be stopped exactly once. +class StoppableBugReporterVisitor : public BugReporterVisitor { + /// This method is run once the \ref Stop method is called. + virtual void OnStop(const ExplodedNode *Curr, BugReporterContext &BRC, + PathSensitiveBugReport &BR) const = 0; + bool Stopped; + +public: + StoppableBugReporterVisitor() : Stopped{false} {} + virtual ~StoppableBugReporterVisitor(); + + /// Call this method once the visitor runs out of useful nodes to process. + void Stop(const ExplodedNode *Curr, BugReporterContext &BRC, + PathSensitiveBugReport &BR); +}; + namespace bugreporter { /// Specifies the type of tracking for an expression. diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -320,6 +320,22 @@ return P; } +//===----------------------------------------------------------------------===// +// Implementation of StoppableBugReporterVisitor +//===----------------------------------------------------------------------===// + +StoppableBugReporterVisitor::~StoppableBugReporterVisitor() { + assert(Stopped && "Stoppable visitor not stopped in its lifetime"); +} + +void StoppableBugReporterVisitor::Stop(const ExplodedNode *Curr, + BugReporterContext &BRC, + PathSensitiveBugReport &BR) { + assert(!Stopped && "Stop() can be called only once in visitor's lifetime"); + Stopped = true; + OnStop(Curr, BRC, BR); +} + //===----------------------------------------------------------------------===// // Implementation of NoStoreFuncVisitor. //===----------------------------------------------------------------------===// @@ -876,6 +892,9 @@ namespace { +using VisitorCallback = llvm::function_ref; + /// Emits an extra note at the return statement of an interesting stack frame. /// /// The returned value is marked as an interesting value, and if it's null, @@ -883,7 +902,7 @@ /// /// This visitor is intended to be used when another visitor discovers that an /// interesting value comes from an inlined function call. -class ReturnVisitor : public BugReporterVisitor { +class ReturnVisitor : public StoppableBugReporterVisitor { const StackFrameContext *CalleeSFC; enum { Initial, @@ -895,12 +914,14 @@ bool ShouldInvalidate = true; AnalyzerOptions& Options; bugreporter::TrackingKind TKind; + VisitorCallback Callback; public: ReturnVisitor(const StackFrameContext *Frame, bool Suppressed, - AnalyzerOptions &Options, bugreporter::TrackingKind TKind) - : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed), - Options(Options), TKind(TKind) {} + AnalyzerOptions &Options, bugreporter::TrackingKind TKind, + VisitorCallback &&Callback = nullptr) + : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed), Options(Options), + TKind(TKind), Callback(Callback) {} static void *getTag() { static int Tag = 0; @@ -913,6 +934,13 @@ ID.AddBoolean(EnableNullFPSuppression); } + void OnStop(const ExplodedNode *Curr, BugReporterContext &BRC, + PathSensitiveBugReport &BR) const override { + if (Callback) { + Callback(Curr, BRC, BR); + } + } + /// Adds a ReturnVisitor if the given statement represents a call that was /// inlined. /// @@ -1123,6 +1151,10 @@ else BR.markInteresting(CalleeSFC); + // Since we know that no other notes will be emitted subsequently by this + // visitor. + Stop(N, BRC, BR); + return EventPiece; }