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