1//===- BugReporter.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 defines BugReporter, a utility class for generating 10// PathDiagnostics for analyses based on ProgramState. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 15#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 16 17#include "clang/Analysis/PathDiagnostic.h" 18#include "clang/Basic/LLVM.h" 19#include "clang/Basic/SourceLocation.h" 20#include "clang/Lex/Preprocessor.h" 21#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" 22#include "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h" 23#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 24#include "clang/StaticAnalyzer/Core/CheckerManager.h" 25#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 26#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 27#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 28#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" 29#include "llvm/ADT/ArrayRef.h" 30#include "llvm/ADT/FoldingSet.h" 31#include "llvm/ADT/ImmutableSet.h" 32#include "llvm/ADT/SmallSet.h" 33#include "llvm/ADT/SmallVector.h" 34#include "llvm/ADT/StringMap.h" 35#include "llvm/ADT/StringRef.h" 36#include "llvm/ADT/ilist.h" 37#include "llvm/ADT/ilist_node.h" 38#include "llvm/ADT/iterator_range.h" 39#include <cassert> 40#include <memory> 41#include <optional> 42#include <string> 43#include <utility> 44#include <vector> 45 46namespace clang { 47 48class AnalyzerOptions; 49class ASTContext; 50class Decl; 51class LocationContext; 52class SourceManager; 53class Stmt; 54 55namespace ento { 56 57class BugType; 58class CheckerBase; 59class ExplodedGraph; 60class ExplodedNode; 61class ExprEngine; 62class MemRegion; 63 64//===----------------------------------------------------------------------===// 65// Interface for individual bug reports. 66//===----------------------------------------------------------------------===// 67 68/// A mapping from diagnostic consumers to the diagnostics they should 69/// consume. 70using DiagnosticForConsumerMapTy = 71 llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>; 72 73/// Interface for classes constructing Stack hints. 74/// 75/// If a PathDiagnosticEvent occurs in a different frame than the final 76/// diagnostic the hints can be used to summarize the effect of the call. 77class StackHintGenerator { 78public: 79 virtual ~StackHintGenerator() = 0; 80 81 /// Construct the Diagnostic message for the given ExplodedNode. 82 virtual std::string getMessage(const ExplodedNode *N) = 0; 83}; 84 85/// Constructs a Stack hint for the given symbol. 86/// 87/// The class knows how to construct the stack hint message based on 88/// traversing the CallExpr associated with the call and checking if the given 89/// symbol is returned or is one of the arguments. 90/// The hint can be customized by redefining 'getMessageForX()' methods. 91class StackHintGeneratorForSymbol : public StackHintGenerator { 92private: 93 SymbolRef Sym; 94 std::string Msg; 95 96public: 97 StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {} 98 ~StackHintGeneratorForSymbol() override = default; 99 100 /// Search the call expression for the symbol Sym and dispatch the 101 /// 'getMessageForX()' methods to construct a specific message. 102 std::string getMessage(const ExplodedNode *N) override; 103 104 /// Produces the message of the following form: 105 /// 'Msg via Nth parameter' 106 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex); 107 108 virtual std::string getMessageForReturn(const CallExpr *CallExpr) { 109 return Msg; 110 } 111 112 virtual std::string getMessageForSymbolNotFound() { 113 return Msg; 114 } 115}; 116 117/// This class provides an interface through which checkers can create 118/// individual bug reports. 119class BugReport { 120public: 121 enum class Kind { Basic, PathSensitive }; 122 123protected: 124 friend class BugReportEquivClass; 125 friend class BugReporter; 126 127 Kind K; 128 const BugType& BT; 129 std::string ShortDescription; 130 std::string Description; 131 132 SmallVector<SourceRange, 4> Ranges; 133 SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> Notes; 134 SmallVector<FixItHint, 4> Fixits; 135 136 BugReport(Kind kind, const BugType &bt, StringRef desc) 137 : BugReport(kind, bt, "", desc) {} 138 139 BugReport(Kind K, const BugType &BT, StringRef ShortDescription, 140 StringRef Description) 141 : K(K), BT(BT), ShortDescription(ShortDescription), 142 Description(Description) {} 143 144public: 145 virtual ~BugReport() = default; 146 147 Kind getKind() const { return K; } 148 149 const BugType& getBugType() const { return BT; } 150 151 /// A verbose warning message that is appropriate for displaying next to 152 /// the source code that introduces the problem. The description should be 153 /// at least a full sentence starting with a capital letter. The period at 154 /// the end of the warning is traditionally omitted. If the description 155 /// consists of multiple sentences, periods between the sentences are 156 /// encouraged, but the period at the end of the description is still omitted. 157 StringRef getDescription() const { return Description; } 158 159 /// A short general warning message that is appropriate for displaying in 160 /// the list of all reported bugs. It should describe what kind of bug is found 161 /// but does not need to try to go into details of that specific bug. 162 /// Grammatical conventions of getDescription() apply here as well. 163 StringRef getShortDescription(bool UseFallback = true) const { 164 if (ShortDescription.empty() && UseFallback) 165 return Description; 166 return ShortDescription; 167 } 168 169 /// The primary location of the bug report that points at the undesirable 170 /// behavior in the code. UIs should attach the warning description to this 171 /// location. The warning description should describe the bad behavior 172 /// at this location. 173 virtual PathDiagnosticLocation getLocation() const = 0; 174 175 /// The smallest declaration that contains the bug location. 176 /// This is purely cosmetic; the declaration can be displayed to the user 177 /// but it does not affect whether the report is emitted. 178 virtual const Decl *getDeclWithIssue() const = 0; 179 180 /// Get the location on which the report should be uniqued. Two warnings are 181 /// considered to be equivalent whenever they have the same bug types, 182 /// descriptions, and uniqueing locations. Out of a class of equivalent 183 /// warnings only one gets displayed to the user. For most warnings the 184 /// uniqueing location coincides with their location, but sometimes 185 /// it makes sense to use different locations. For example, a leak 186 /// checker can place the warning at the location where the last reference 187 /// to the leaking resource is dropped but at the same time unique the warning 188 /// by where that resource is acquired (allocated). 189 virtual PathDiagnosticLocation getUniqueingLocation() const = 0; 190 191 /// Get the declaration that corresponds to (usually contains) the uniqueing 192 /// location. This is not actively used for uniqueing, i.e. otherwise 193 /// identical reports that have different uniqueing decls will be considered 194 /// equivalent. 195 virtual const Decl *getUniqueingDecl() const = 0; 196 197 /// Add new item to the list of additional notes that need to be attached to 198 /// this report. If the report is path-sensitive, these notes will not be 199 /// displayed as part of the execution path explanation, but will be displayed 200 /// separately. Use bug visitors if you need to add an extra path note. 201 void addNote(StringRef Msg, const PathDiagnosticLocation &Pos, 202 ArrayRef<SourceRange> Ranges = {}) { 203 auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg); 204 205 for (const auto &R : Ranges) 206 P->addRange(R); 207 208 Notes.push_back(std::move(P)); 209 } 210 211 ArrayRef<std::shared_ptr<PathDiagnosticNotePiece>> getNotes() { 212 return Notes; 213 } 214 215 /// Add a range to a bug report. 216 /// 217 /// Ranges are used to highlight regions of interest in the source code. 218 /// They should be at the same source code line as the BugReport location. 219 /// By default, the source range of the statement corresponding to the error 220 /// node will be used; add a single invalid range to specify absence of 221 /// ranges. 222 void addRange(SourceRange R) { 223 assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used " 224 "to specify that the report does not have a range."); 225 Ranges.push_back(R); 226 } 227 228 /// Get the SourceRanges associated with the report. 229 virtual ArrayRef<SourceRange> getRanges() const { 230 return Ranges; 231 } 232 233 /// Add a fix-it hint to the bug report. 234 /// 235 /// Fix-it hints are the suggested edits to the code that would resolve 236 /// the problem explained by the bug report. Fix-it hints should be 237 /// as conservative as possible because it is not uncommon for the user 238 /// to blindly apply all fixits to their project. Note that it is very hard 239 /// to produce a good fix-it hint for most path-sensitive warnings. 240 void addFixItHint(const FixItHint &F) { 241 Fixits.push_back(F); 242 } 243 244 llvm::ArrayRef<FixItHint> getFixits() const { return Fixits; } 245 246 /// Reports are uniqued to ensure that we do not emit multiple diagnostics 247 /// for each bug. 248 virtual void Profile(llvm::FoldingSetNodeID& hash) const = 0; 249}; 250 251class BasicBugReport : public BugReport { 252 PathDiagnosticLocation Location; 253 const Decl *DeclWithIssue = nullptr; 254 255public: 256 BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l) 257 : BugReport(Kind::Basic, bt, desc), Location(l) {} 258 259 static bool classof(const BugReport *R) { 260 return R->getKind() == Kind::Basic; 261 } 262 263 PathDiagnosticLocation getLocation() const override { 264 assert(Location.isValid()); 265 return Location; 266 } 267 268 const Decl *getDeclWithIssue() const override { 269 return DeclWithIssue; 270 } 271 272 PathDiagnosticLocation getUniqueingLocation() const override { 273 return getLocation(); 274 } 275 276 const Decl *getUniqueingDecl() const override { 277 return getDeclWithIssue(); 278 } 279 280 /// Specifically set the Decl where an issue occurred. This isn't necessary 281 /// for BugReports that cover a path as it will be automatically inferred. 282 void setDeclWithIssue(const Decl *declWithIssue) { 283 DeclWithIssue = declWithIssue; 284 } 285 286 void Profile(llvm::FoldingSetNodeID& hash) const override; 287}; 288 289class PathSensitiveBugReport : public BugReport { 290public: 291 using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>; 292 using visitor_iterator = VisitorList::iterator; 293 using visitor_range = llvm::iterator_range<visitor_iterator>; 294 295protected: 296 /// The ExplodedGraph node against which the report was thrown. It corresponds 297 /// to the end of the execution path that demonstrates the bug. 298 const ExplodedNode *ErrorNode = nullptr; 299 300 /// The range that corresponds to ErrorNode's program point. It is usually 301 /// highlighted in the report. 302 const SourceRange ErrorNodeRange; 303 304 /// Profile to identify equivalent bug reports for error report coalescing. 305 306 /// A (stack of) a set of symbols that are registered with this 307 /// report as being "interesting", and thus used to help decide which 308 /// diagnostics to include when constructing the final path diagnostic. 309 /// The stack is largely used by BugReporter when generating PathDiagnostics 310 /// for multiple PathDiagnosticConsumers. 311 llvm::DenseMap<SymbolRef, bugreporter::TrackingKind> InterestingSymbols; 312 313 /// A (stack of) set of regions that are registered with this report as being 314 /// "interesting", and thus used to help decide which diagnostics 315 /// to include when constructing the final path diagnostic. 316 /// The stack is largely used by BugReporter when generating PathDiagnostics 317 /// for multiple PathDiagnosticConsumers. 318 llvm::DenseMap<const MemRegion *, bugreporter::TrackingKind> 319 InterestingRegions; 320 321 /// A set of location contexts that correspoind to call sites which should be 322 /// considered "interesting". 323 llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts; 324 325 /// A set of custom visitors which generate "event" diagnostics at 326 /// interesting points in the path. 327 VisitorList Callbacks; 328 329 /// Used for ensuring the visitors are only added once. 330 llvm::FoldingSet<BugReporterVisitor> CallbacksSet; 331 332 /// When set, this flag disables all callstack pruning from a diagnostic 333 /// path. This is useful for some reports that want maximum fidelty 334 /// when reporting an issue. 335 bool DoNotPrunePath = false; 336 337 /// Used to track unique reasons why a bug report might be invalid. 338 /// 339 /// \sa markInvalid 340 /// \sa removeInvalidation 341 using InvalidationRecord = std::pair<const void *, const void *>; 342 343 /// If non-empty, this bug report is likely a false positive and should not be 344 /// shown to the user. 345 /// 346 /// \sa markInvalid 347 /// \sa removeInvalidation 348 llvm::SmallSet<InvalidationRecord, 4> Invalidations; 349 350 /// Conditions we're already tracking. 351 llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions; 352 353 /// Reports with different uniqueing locations are considered to be different 354 /// for the purposes of deduplication. 355 PathDiagnosticLocation UniqueingLocation; 356 const Decl *UniqueingDecl; 357 358 const Stmt *getStmt() const; 359 360 /// If an event occurs in a different frame than the final diagnostic, 361 /// supply a message that will be used to construct an extra hint on the 362 /// returns from all the calls on the stack from this event to the final 363 /// diagnostic. 364 // FIXME: Allow shared_ptr keys in DenseMap? 365 std::map<PathDiagnosticPieceRef, std::unique_ptr<StackHintGenerator>> 366 StackHints; 367 368public: 369 PathSensitiveBugReport(const BugType &bt, StringRef desc, 370 const ExplodedNode *errorNode) 371 : PathSensitiveBugReport(bt, desc, desc, errorNode) {} 372 373 PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc, 374 const ExplodedNode *errorNode) 375 : PathSensitiveBugReport(bt, shortDesc, desc, errorNode, 376 /*LocationToUnique*/ {}, 377 /*DeclToUnique*/ nullptr) {} 378 379 /// Create a PathSensitiveBugReport with a custom uniqueing location. 380 /// 381 /// The reports that have the same report location, description, bug type, and 382 /// ranges are uniqued - only one of the equivalent reports will be presented 383 /// to the user. This method allows to rest the location which should be used 384 /// for uniquing reports. For example, memory leaks checker, could set this to 385 /// the allocation site, rather then the location where the bug is reported. 386 PathSensitiveBugReport(const BugType &bt, StringRef desc, 387 const ExplodedNode *errorNode, 388 PathDiagnosticLocation LocationToUnique, 389 const Decl *DeclToUnique) 390 : PathSensitiveBugReport(bt, desc, desc, errorNode, LocationToUnique, 391 DeclToUnique) {} 392 393 PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc, 394 const ExplodedNode *errorNode, 395 PathDiagnosticLocation LocationToUnique, 396 const Decl *DeclToUnique); 397 398 static bool classof(const BugReport *R) { 399 return R->getKind() == Kind::PathSensitive; 400 } 401 402 const ExplodedNode *getErrorNode() const { return ErrorNode; } 403 404 /// Indicates whether or not any path pruning should take place 405 /// when generating a PathDiagnostic from this BugReport. 406 bool shouldPrunePath() const { return !DoNotPrunePath; } 407 408 /// Disable all path pruning when generating a PathDiagnostic. 409 void disablePathPruning() { DoNotPrunePath = true; } 410 411 /// Get the location on which the report should be uniqued. 412 PathDiagnosticLocation getUniqueingLocation() const override { 413 return UniqueingLocation; 414 } 415 416 /// Get the declaration containing the uniqueing location. 417 const Decl *getUniqueingDecl() const override { 418 return UniqueingDecl; 419 } 420 421 const Decl *getDeclWithIssue() const override; 422 423 ArrayRef<SourceRange> getRanges() const override; 424 425 PathDiagnosticLocation getLocation() const override; 426 427 /// Marks a symbol as interesting. Different kinds of interestingness will 428 /// be processed differently by visitors (e.g. if the tracking kind is 429 /// condition, will append "will be used as a condition" to the message). 430 void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind = 431 bugreporter::TrackingKind::Thorough); 432 433 void markNotInteresting(SymbolRef sym); 434 435 /// Marks a region as interesting. Different kinds of interestingness will 436 /// be processed differently by visitors (e.g. if the tracking kind is 437 /// condition, will append "will be used as a condition" to the message). 438 void markInteresting( 439 const MemRegion *R, 440 bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough); 441 442 void markNotInteresting(const MemRegion *R); 443 444 /// Marks a symbolic value as interesting. Different kinds of interestingness 445 /// will be processed differently by visitors (e.g. if the tracking kind is 446 /// condition, will append "will be used as a condition" to the message). 447 void markInteresting(SVal V, bugreporter::TrackingKind TKind = 448 bugreporter::TrackingKind::Thorough); 449 void markInteresting(const LocationContext *LC); 450 451 bool isInteresting(SymbolRef sym) const; 452 bool isInteresting(const MemRegion *R) const; 453 bool isInteresting(SVal V) const; 454 bool isInteresting(const LocationContext *LC) const; 455 456 std::optional<bugreporter::TrackingKind> 457 getInterestingnessKind(SymbolRef sym) const; 458 459 std::optional<bugreporter::TrackingKind> 460 getInterestingnessKind(const MemRegion *R) const; 461 462 std::optional<bugreporter::TrackingKind> getInterestingnessKind(SVal V) const; 463 464 /// Returns whether or not this report should be considered valid. 465 /// 466 /// Invalid reports are those that have been classified as likely false 467 /// positives after the fact. 468 bool isValid() const { 469 return Invalidations.empty(); 470 } 471 472 /// Marks the current report as invalid, meaning that it is probably a false 473 /// positive and should not be reported to the user. 474 /// 475 /// The \p Tag and \p Data arguments are intended to be opaque identifiers for 476 /// this particular invalidation, where \p Tag represents the visitor 477 /// responsible for invalidation, and \p Data represents the reason this 478 /// visitor decided to invalidate the bug report. 479 /// 480 /// \sa removeInvalidation 481 void markInvalid(const void *Tag, const void *Data) { 482 Invalidations.insert(std::make_pair(Tag, Data)); 483 } 484 485 /// Profile to identify equivalent bug reports for error report coalescing. 486 /// Reports are uniqued to ensure that we do not emit multiple diagnostics 487 /// for each bug. 488 void Profile(llvm::FoldingSetNodeID &hash) const override; 489 490 /// Add custom or predefined bug report visitors to this report. 491 /// 492 /// The visitors should be used when the default trace is not sufficient. 493 /// For example, they allow constructing a more elaborate trace. 494 /// @{ 495 void addVisitor(std::unique_ptr<BugReporterVisitor> visitor); 496 497 template <class VisitorType, class... Args> 498 void addVisitor(Args &&... ConstructorArgs) { 499 addVisitor( 500 std::make_unique<VisitorType>(std::forward<Args>(ConstructorArgs)...)); 501 } 502 /// @} 503 504 /// Remove all visitors attached to this bug report. 505 void clearVisitors(); 506 507 /// Iterators through the custom diagnostic visitors. 508 visitor_iterator visitor_begin() { return Callbacks.begin(); } 509 visitor_iterator visitor_end() { return Callbacks.end(); } 510 visitor_range visitors() { return {visitor_begin(), visitor_end()}; } 511 512 /// Notes that the condition of the CFGBlock associated with \p Cond is 513 /// being tracked. 514 /// \returns false if the condition is already being tracked. 515 bool addTrackedCondition(const ExplodedNode *Cond) { 516 return TrackedConditions.insert(Cond).second; 517 } 518 519 void addCallStackHint(PathDiagnosticPieceRef Piece, 520 std::unique_ptr<StackHintGenerator> StackHint) { 521 StackHints[Piece] = std::move(StackHint); 522 } 523 524 bool hasCallStackHint(PathDiagnosticPieceRef Piece) const { 525 return StackHints.count(Piece) > 0; 526 } 527 528 /// Produce the hint for the given node. The node contains 529 /// information about the call for which the diagnostic can be generated. 530 std::string 531 getCallStackMessage(PathDiagnosticPieceRef Piece, 532 const ExplodedNode *N) const { 533 auto I = StackHints.find(Piece); 534 if (I != StackHints.end()) 535 return I->second->getMessage(N); 536 return ""; 537 } 538}; 539 540//===----------------------------------------------------------------------===// 541// BugTypes (collections of related reports). 542//===----------------------------------------------------------------------===// 543 544class BugReportEquivClass : public llvm::FoldingSetNode { 545 friend class BugReporter; 546 547 /// List of *owned* BugReport objects. 548 llvm::SmallVector<std::unique_ptr<BugReport>, 4> Reports; 549 550 void AddReport(std::unique_ptr<BugReport> &&R) { 551 Reports.push_back(std::move(R)); 552 } 553 554public: 555 BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); } 556 557 ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; } 558 559 void Profile(llvm::FoldingSetNodeID& ID) const { 560 assert(!Reports.empty()); 561 Reports.front()->Profile(ID); 562 } 563}; 564 565//===----------------------------------------------------------------------===// 566// BugReporter and friends. 567//===----------------------------------------------------------------------===// 568 569class BugReporterData { 570public: 571 virtual ~BugReporterData() = default; 572 573 virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; 574 virtual ASTContext &getASTContext() = 0; 575 virtual SourceManager &getSourceManager() = 0; 576 virtual AnalyzerOptions &getAnalyzerOptions() = 0; 577 virtual Preprocessor &getPreprocessor() = 0; 578}; 579 580/// BugReporter is a utility class for generating PathDiagnostics for analysis. 581/// It collects the BugReports and BugTypes and knows how to generate 582/// and flush the corresponding diagnostics. 583/// 584/// The base class is used for generating path-insensitive 585class BugReporter { 586private: 587 BugReporterData& D; 588 589 /// Generate and flush the diagnostics for the given bug report. 590 void FlushReport(BugReportEquivClass& EQ); 591 592 /// The set of bug reports tracked by the BugReporter. 593 llvm::FoldingSet<BugReportEquivClass> EQClasses; 594 595 /// A vector of BugReports for tracking the allocated pointers and cleanup. 596 std::vector<BugReportEquivClass *> EQClassesVector; 597 598 /// User-provided in-code suppressions. 599 BugSuppression UserSuppressions; 600 601public: 602 BugReporter(BugReporterData &d); 603 virtual ~BugReporter(); 604 605 /// Generate and flush diagnostics for all bug reports. 606 void FlushReports(); 607 608 ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { 609 return D.getPathDiagnosticConsumers(); 610 } 611 612 /// Iterator over the set of BugReports tracked by the BugReporter. 613 using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator; 614 llvm::iterator_range<EQClasses_iterator> equivalenceClasses() { 615 return EQClasses; 616 } 617 618 ASTContext &getContext() { return D.getASTContext(); } 619 620 const SourceManager &getSourceManager() { return D.getSourceManager(); } 621 622 const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); } 623 624 Preprocessor &getPreprocessor() { return D.getPreprocessor(); } 625 626 /// Add the given report to the set of reports tracked by BugReporter. 627 /// 628 /// The reports are usually generated by the checkers. Further, they are 629 /// folded based on the profile value, which is done to coalesce similar 630 /// reports. 631 virtual void emitReport(std::unique_ptr<BugReport> R); 632 633 void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, 634 StringRef BugName, StringRef BugCategory, 635 StringRef BugStr, PathDiagnosticLocation Loc, 636 ArrayRef<SourceRange> Ranges = std::nullopt, 637 ArrayRef<FixItHint> Fixits = std::nullopt); 638 639 void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName, 640 StringRef BugName, StringRef BugCategory, 641 StringRef BugStr, PathDiagnosticLocation Loc, 642 ArrayRef<SourceRange> Ranges = std::nullopt, 643 ArrayRef<FixItHint> Fixits = std::nullopt); 644 645private: 646 llvm::StringMap<std::unique_ptr<BugType>> StrBugTypes; 647 648 /// Returns a BugType that is associated with the given name and 649 /// category. 650 BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name, 651 StringRef category); 652 653 virtual BugReport * 654 findReportInEquivalenceClass(BugReportEquivClass &eqClass, 655 SmallVectorImpl<BugReport *> &bugReports) { 656 return eqClass.getReports()[0].get(); 657 } 658 659protected: 660 /// Generate the diagnostics for the given bug report. 661 virtual std::unique_ptr<DiagnosticForConsumerMapTy> 662 generateDiagnosticForConsumerMap(BugReport *exampleReport, 663 ArrayRef<PathDiagnosticConsumer *> consumers, 664 ArrayRef<BugReport *> bugReports); 665}; 666 667/// GRBugReporter is used for generating path-sensitive reports. 668class PathSensitiveBugReporter final : public BugReporter { 669 ExprEngine& Eng; 670 671 BugReport *findReportInEquivalenceClass( 672 BugReportEquivClass &eqClass, 673 SmallVectorImpl<BugReport *> &bugReports) override; 674 675 /// Generate the diagnostics for the given bug report. 676 std::unique_ptr<DiagnosticForConsumerMapTy> 677 generateDiagnosticForConsumerMap(BugReport *exampleReport, 678 ArrayRef<PathDiagnosticConsumer *> consumers, 679 ArrayRef<BugReport *> bugReports) override; 680public: 681 PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng) 682 : BugReporter(d), Eng(eng) {} 683 684 /// getGraph - Get the exploded graph created by the analysis engine 685 /// for the analyzed method or function. 686 const ExplodedGraph &getGraph() const; 687 688 /// getStateManager - Return the state manager used by the analysis 689 /// engine. 690 ProgramStateManager &getStateManager() const; 691 692 /// \p bugReports A set of bug reports within a *single* equivalence class 693 /// 694 /// \return A mapping from consumers to the corresponding diagnostics. 695 /// Iterates through the bug reports within a single equivalence class, 696 /// stops at a first non-invalidated report. 697 std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics( 698 ArrayRef<PathDiagnosticConsumer *> consumers, 699 ArrayRef<PathSensitiveBugReport *> &bugReports); 700 701 void emitReport(std::unique_ptr<BugReport> R) override; 702}; 703 704 705class BugReporterContext { 706 PathSensitiveBugReporter &BR; 707 708 virtual void anchor(); 709 710public: 711 BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {} 712 713 virtual ~BugReporterContext() = default; 714 715 PathSensitiveBugReporter& getBugReporter() { return BR; } 716 717 ProgramStateManager& getStateManager() const { 718 return BR.getStateManager(); 719 } 720 721 ASTContext &getASTContext() const { 722 return BR.getContext(); 723 } 724 725 const SourceManager& getSourceManager() const { 726 return BR.getSourceManager(); 727 } 728 729 const AnalyzerOptions &getAnalyzerOptions() const { 730 return BR.getAnalyzerOptions(); 731 } 732}; 733 734/// The tag that carries some information with it. 735/// 736/// It can be valuable to produce tags with some bits of information and later 737/// reuse them for a better diagnostic. 738/// 739/// Please make sure that derived class' constuctor is private and that the user 740/// can only create objects using DataTag::Factory. This also means that 741/// DataTag::Factory should be friend for every derived class. 742class DataTag : public ProgramPointTag { 743public: 744 StringRef getTagDescription() const override { return "Data Tag"; } 745 746 // Manage memory for DataTag objects. 747 class Factory { 748 std::vector<std::unique_ptr<DataTag>> Tags; 749 750 public: 751 template <class DataTagType, class... Args> 752 const DataTagType *make(Args &&... ConstructorArgs) { 753 // We cannot use std::make_unique because we cannot access the private 754 // constructor from inside it. 755 Tags.emplace_back( 756 new DataTagType(std::forward<Args>(ConstructorArgs)...)); 757 return static_cast<DataTagType *>(Tags.back().get()); 758 } 759 }; 760 761protected: 762 DataTag(void *TagKind) : ProgramPointTag(TagKind) {} 763}; 764 765/// The tag upon which the TagVisitor reacts. Add these in order to display 766/// additional PathDiagnosticEventPieces along the path. 767class NoteTag : public DataTag { 768public: 769 using Callback = std::function<std::string(BugReporterContext &, 770 PathSensitiveBugReport &)>; 771 772private: 773 static int Kind; 774 775 const Callback Cb; 776 const bool IsPrunable; 777 778 NoteTag(Callback &&Cb, bool IsPrunable) 779 : DataTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {} 780 781public: 782 static bool classof(const ProgramPointTag *T) { 783 return T->getTagKind() == &Kind; 784 } 785 786 std::optional<std::string> generateMessage(BugReporterContext &BRC, 787 PathSensitiveBugReport &R) const { 788 std::string Msg = Cb(BRC, R); 789 if (Msg.empty()) 790 return std::nullopt; 791 792 return std::move(Msg); 793 } 794 795 StringRef getTagDescription() const override { 796 // TODO: Remember a few examples of generated messages 797 // and display them in the ExplodedGraph dump by 798 // returning them from this function. 799 return "Note Tag"; 800 } 801 802 bool isPrunable() const { return IsPrunable; } 803 804 friend class Factory; 805 friend class TagVisitor; 806}; 807 808} // namespace ento 809 810} // namespace clang 811 812#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 813