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