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,30 @@ 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); +}; + +// Callback type for trackExpressionValue +using VisitorCallback = llvm::function_ref; + namespace bugreporter { /// Specifies the type of tracking for an expression. @@ -114,7 +138,8 @@ bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingKind TKind = TrackingKind::Thorough, - bool EnableNullFPSuppression = true); + bool EnableNullFPSuppression = true, + VisitorCallback Callback = nullptr); const Expr *getDerefExpr(const Stmt *S); 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. //===----------------------------------------------------------------------===// @@ -883,7 +899,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 +911,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) + : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed), Options(Options), + TKind(TKind), Callback(Callback) {} static void *getTag() { static int Tag = 0; @@ -913,6 +931,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. /// @@ -923,7 +948,8 @@ static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S, PathSensitiveBugReport &BR, bool InEnableNullFPSuppression, - bugreporter::TrackingKind TKind) { + bugreporter::TrackingKind TKind, + VisitorCallback Callback) { if (!CallEvent::isCallStmt(S)) return; @@ -994,9 +1020,9 @@ if (Optional RetLoc = RetVal.getAs()) EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue(); - BR.addVisitor(std::make_unique(CalleeContext, - EnableNullFPSuppression, - Options, TKind)); + BR.addVisitor( + std::make_unique(CalleeContext, EnableNullFPSuppression, + Options, TKind, std::move(Callback))); } PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N, @@ -1123,6 +1149,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; } @@ -1966,7 +1996,8 @@ const Expr *E, PathSensitiveBugReport &report, bugreporter::TrackingKind TKind, - bool EnableNullFPSuppression) { + bool EnableNullFPSuppression, + VisitorCallback Callback) { if (!E || !InputNode) return false; @@ -2067,7 +2098,7 @@ SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext()); ReturnVisitor::addVisitorIfNecessary( - LVNode, Inner, report, EnableNullFPSuppression, TKind); + LVNode, Inner, report, EnableNullFPSuppression, TKind, Callback); // Is it a symbolic value? if (auto L = V.getAs()) {