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 46 namespace clang { 47 48 class AnalyzerOptions; 49 class ASTContext; 50 class Decl; 51 class LocationContext; 52 class SourceManager; 53 class Stmt; 54 55 namespace ento { 56 57 class BugType; 58 class CheckerBase; 59 class ExplodedGraph; 60 class ExplodedNode; 61 class ExprEngine; 62 class MemRegion; 63 64 //===----------------------------------------------------------------------===// 65 // Interface for individual bug reports. 66 //===----------------------------------------------------------------------===// 67 68 /// A mapping from diagnostic consumers to the diagnostics they should 69 /// consume. 70 using 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. 77 class StackHintGenerator { 78 public: 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. 91 class StackHintGeneratorForSymbol : public StackHintGenerator { 92 private: 93 SymbolRef Sym; 94 std::string Msg; 95 96 public: StackHintGeneratorForSymbol(SymbolRef S,StringRef M)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 getMessageForReturn(const CallExpr * CallExpr)108 virtual std::string getMessageForReturn(const CallExpr *CallExpr) { 109 return Msg; 110 } 111 getMessageForSymbolNotFound()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. 119 class BugReport { 120 public: 121 enum class Kind { Basic, PathSensitive }; 122 123 protected: 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 BugReport(Kind kind,const BugType & bt,StringRef desc)136 BugReport(Kind kind, const BugType &bt, StringRef desc) 137 : BugReport(kind, bt, "", desc) {} 138 BugReport(Kind K,const BugType & BT,StringRef ShortDescription,StringRef Description)139 BugReport(Kind K, const BugType &BT, StringRef ShortDescription, 140 StringRef Description) 141 : K(K), BT(BT), ShortDescription(ShortDescription), 142 Description(Description) {} 143 144 public: 145 virtual ~BugReport() = default; 146 getKind()147 Kind getKind() const { return K; } 148 getBugType()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. getDescription()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 getNotes()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. addRange(SourceRange R)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. getRanges()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. addFixItHint(const FixItHint & F)240 void addFixItHint(const FixItHint &F) { 241 Fixits.push_back(F); 242 } 243 getFixits()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 251 class BasicBugReport : public BugReport { 252 PathDiagnosticLocation Location; 253 const Decl *DeclWithIssue = nullptr; 254 255 public: BasicBugReport(const BugType & bt,StringRef desc,PathDiagnosticLocation l)256 BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l) 257 : BugReport(Kind::Basic, bt, desc), Location(l) {} 258 classof(const BugReport * R)259 static bool classof(const BugReport *R) { 260 return R->getKind() == Kind::Basic; 261 } 262 getLocation()263 PathDiagnosticLocation getLocation() const override { 264 assert(Location.isValid()); 265 return Location; 266 } 267 getDeclWithIssue()268 const Decl *getDeclWithIssue() const override { 269 return DeclWithIssue; 270 } 271 getUniqueingLocation()272 PathDiagnosticLocation getUniqueingLocation() const override { 273 return getLocation(); 274 } 275 getUniqueingDecl()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. setDeclWithIssue(const Decl * declWithIssue)282 void setDeclWithIssue(const Decl *declWithIssue) { 283 DeclWithIssue = declWithIssue; 284 } 285 286 void Profile(llvm::FoldingSetNodeID& hash) const override; 287 }; 288 289 class PathSensitiveBugReport : public BugReport { 290 public: 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 295 protected: 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 368 public: PathSensitiveBugReport(const BugType & bt,StringRef desc,const ExplodedNode * errorNode)369 PathSensitiveBugReport(const BugType &bt, StringRef desc, 370 const ExplodedNode *errorNode) 371 : PathSensitiveBugReport(bt, desc, desc, errorNode) {} 372 PathSensitiveBugReport(const BugType & bt,StringRef shortDesc,StringRef desc,const ExplodedNode * errorNode)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. PathSensitiveBugReport(const BugType & bt,StringRef desc,const ExplodedNode * errorNode,PathDiagnosticLocation LocationToUnique,const Decl * DeclToUnique)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 classof(const BugReport * R)398 static bool classof(const BugReport *R) { 399 return R->getKind() == Kind::PathSensitive; 400 } 401 getErrorNode()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. shouldPrunePath()406 bool shouldPrunePath() const { return !DoNotPrunePath; } 407 408 /// Disable all path pruning when generating a PathDiagnostic. disablePathPruning()409 void disablePathPruning() { DoNotPrunePath = true; } 410 411 /// Get the location on which the report should be uniqued. getUniqueingLocation()412 PathDiagnosticLocation getUniqueingLocation() const override { 413 return UniqueingLocation; 414 } 415 416 /// Get the declaration containing the uniqueing location. getUniqueingDecl()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. isValid()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 markInvalid(const void * Tag,const void * Data)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> addVisitor(Args &&...ConstructorArgs)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. visitor_begin()508 visitor_iterator visitor_begin() { return Callbacks.begin(); } visitor_end()509 visitor_iterator visitor_end() { return Callbacks.end(); } visitors()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. addTrackedCondition(const ExplodedNode * Cond)515 bool addTrackedCondition(const ExplodedNode *Cond) { 516 return TrackedConditions.insert(Cond).second; 517 } 518 addCallStackHint(PathDiagnosticPieceRef Piece,std::unique_ptr<StackHintGenerator> StackHint)519 void addCallStackHint(PathDiagnosticPieceRef Piece, 520 std::unique_ptr<StackHintGenerator> StackHint) { 521 StackHints[Piece] = std::move(StackHint); 522 } 523 hasCallStackHint(PathDiagnosticPieceRef Piece)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 getCallStackMessage(PathDiagnosticPieceRef Piece,const ExplodedNode * N)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 544 class 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 AddReport(std::unique_ptr<BugReport> && R)550 void AddReport(std::unique_ptr<BugReport> &&R) { 551 Reports.push_back(std::move(R)); 552 } 553 554 public: BugReportEquivClass(std::unique_ptr<BugReport> R)555 BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); } 556 getReports()557 ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; } 558 Profile(llvm::FoldingSetNodeID & ID)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 569 class BugReporterData { 570 public: 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 585 class BugReporter { 586 private: 587 BugReporterData& D; 588 589 /// The top-level entry point for the issue to be reported. 590 const Decl *AnalysisEntryPoint = nullptr; 591 592 /// Generate and flush the diagnostics for the given bug report. 593 void FlushReport(BugReportEquivClass& EQ); 594 595 /// The set of bug reports tracked by the BugReporter. 596 llvm::FoldingSet<BugReportEquivClass> EQClasses; 597 598 /// A vector of BugReports for tracking the allocated pointers and cleanup. 599 std::vector<BugReportEquivClass *> EQClassesVector; 600 601 /// User-provided in-code suppressions. 602 BugSuppression UserSuppressions; 603 604 public: 605 BugReporter(BugReporterData &d); 606 virtual ~BugReporter(); 607 608 /// Generate and flush diagnostics for all bug reports. 609 void FlushReports(); 610 getPathDiagnosticConsumers()611 ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { 612 return D.getPathDiagnosticConsumers(); 613 } 614 615 /// Iterator over the set of BugReports tracked by the BugReporter. 616 using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator; equivalenceClasses()617 llvm::iterator_range<EQClasses_iterator> equivalenceClasses() { 618 return EQClasses; 619 } 620 getContext()621 ASTContext &getContext() { return D.getASTContext(); } 622 getSourceManager()623 const SourceManager &getSourceManager() { return D.getSourceManager(); } 624 getAnalyzerOptions()625 const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); } 626 getPreprocessor()627 Preprocessor &getPreprocessor() { return D.getPreprocessor(); } 628 629 /// Get the top-level entry point for the issue to be reported. getAnalysisEntryPoint()630 const Decl *getAnalysisEntryPoint() const { return AnalysisEntryPoint; } 631 setAnalysisEntryPoint(const Decl * EntryPoint)632 void setAnalysisEntryPoint(const Decl *EntryPoint) { 633 assert(EntryPoint); 634 AnalysisEntryPoint = EntryPoint; 635 } 636 637 /// Add the given report to the set of reports tracked by BugReporter. 638 /// 639 /// The reports are usually generated by the checkers. Further, they are 640 /// folded based on the profile value, which is done to coalesce similar 641 /// reports. 642 virtual void emitReport(std::unique_ptr<BugReport> R); 643 644 void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, 645 StringRef BugName, StringRef BugCategory, 646 StringRef BugStr, PathDiagnosticLocation Loc, 647 ArrayRef<SourceRange> Ranges = std::nullopt, 648 ArrayRef<FixItHint> Fixits = std::nullopt); 649 650 void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName, 651 StringRef BugName, StringRef BugCategory, 652 StringRef BugStr, PathDiagnosticLocation Loc, 653 ArrayRef<SourceRange> Ranges = std::nullopt, 654 ArrayRef<FixItHint> Fixits = std::nullopt); 655 656 private: 657 llvm::StringMap<std::unique_ptr<BugType>> StrBugTypes; 658 659 /// Returns a BugType that is associated with the given name and 660 /// category. 661 BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name, 662 StringRef category); 663 664 virtual BugReport * findReportInEquivalenceClass(BugReportEquivClass & eqClass,SmallVectorImpl<BugReport * > & bugReports)665 findReportInEquivalenceClass(BugReportEquivClass &eqClass, 666 SmallVectorImpl<BugReport *> &bugReports) { 667 return eqClass.getReports()[0].get(); 668 } 669 670 protected: 671 /// Generate the diagnostics for the given bug report. 672 virtual std::unique_ptr<DiagnosticForConsumerMapTy> 673 generateDiagnosticForConsumerMap(BugReport *exampleReport, 674 ArrayRef<PathDiagnosticConsumer *> consumers, 675 ArrayRef<BugReport *> bugReports); 676 }; 677 678 /// GRBugReporter is used for generating path-sensitive reports. 679 class PathSensitiveBugReporter final : public BugReporter { 680 ExprEngine& Eng; 681 682 BugReport *findReportInEquivalenceClass( 683 BugReportEquivClass &eqClass, 684 SmallVectorImpl<BugReport *> &bugReports) override; 685 686 /// Generate the diagnostics for the given bug report. 687 std::unique_ptr<DiagnosticForConsumerMapTy> 688 generateDiagnosticForConsumerMap(BugReport *exampleReport, 689 ArrayRef<PathDiagnosticConsumer *> consumers, 690 ArrayRef<BugReport *> bugReports) override; 691 public: PathSensitiveBugReporter(BugReporterData & d,ExprEngine & eng)692 PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng) 693 : BugReporter(d), Eng(eng) {} 694 695 /// getGraph - Get the exploded graph created by the analysis engine 696 /// for the analyzed method or function. 697 const ExplodedGraph &getGraph() const; 698 699 /// getStateManager - Return the state manager used by the analysis 700 /// engine. 701 ProgramStateManager &getStateManager() const; 702 703 /// \p bugReports A set of bug reports within a *single* equivalence class 704 /// 705 /// \return A mapping from consumers to the corresponding diagnostics. 706 /// Iterates through the bug reports within a single equivalence class, 707 /// stops at a first non-invalidated report. 708 std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics( 709 ArrayRef<PathDiagnosticConsumer *> consumers, 710 ArrayRef<PathSensitiveBugReport *> &bugReports); 711 712 void emitReport(std::unique_ptr<BugReport> R) override; 713 }; 714 715 716 class BugReporterContext { 717 PathSensitiveBugReporter &BR; 718 719 virtual void anchor(); 720 721 public: BugReporterContext(PathSensitiveBugReporter & br)722 BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {} 723 724 virtual ~BugReporterContext() = default; 725 getBugReporter()726 PathSensitiveBugReporter& getBugReporter() { return BR; } getBugReporter()727 const PathSensitiveBugReporter &getBugReporter() const { return BR; } 728 getStateManager()729 ProgramStateManager& getStateManager() const { 730 return BR.getStateManager(); 731 } 732 getASTContext()733 ASTContext &getASTContext() const { 734 return BR.getContext(); 735 } 736 getSourceManager()737 const SourceManager& getSourceManager() const { 738 return BR.getSourceManager(); 739 } 740 getAnalyzerOptions()741 const AnalyzerOptions &getAnalyzerOptions() const { 742 return BR.getAnalyzerOptions(); 743 } 744 }; 745 746 /// The tag that carries some information with it. 747 /// 748 /// It can be valuable to produce tags with some bits of information and later 749 /// reuse them for a better diagnostic. 750 /// 751 /// Please make sure that derived class' constuctor is private and that the user 752 /// can only create objects using DataTag::Factory. This also means that 753 /// DataTag::Factory should be friend for every derived class. 754 class DataTag : public ProgramPointTag { 755 public: getTagDescription()756 StringRef getTagDescription() const override { return "Data Tag"; } 757 758 // Manage memory for DataTag objects. 759 class Factory { 760 std::vector<std::unique_ptr<DataTag>> Tags; 761 762 public: 763 template <class DataTagType, class... Args> make(Args &&...ConstructorArgs)764 const DataTagType *make(Args &&... ConstructorArgs) { 765 // We cannot use std::make_unique because we cannot access the private 766 // constructor from inside it. 767 Tags.emplace_back( 768 new DataTagType(std::forward<Args>(ConstructorArgs)...)); 769 return static_cast<DataTagType *>(Tags.back().get()); 770 } 771 }; 772 773 protected: DataTag(void * TagKind)774 DataTag(void *TagKind) : ProgramPointTag(TagKind) {} 775 }; 776 777 /// The tag upon which the TagVisitor reacts. Add these in order to display 778 /// additional PathDiagnosticEventPieces along the path. 779 class NoteTag : public DataTag { 780 public: 781 using Callback = std::function<std::string(BugReporterContext &, 782 PathSensitiveBugReport &)>; 783 784 private: 785 static int Kind; 786 787 const Callback Cb; 788 const bool IsPrunable; 789 NoteTag(Callback && Cb,bool IsPrunable)790 NoteTag(Callback &&Cb, bool IsPrunable) 791 : DataTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {} 792 793 public: classof(const ProgramPointTag * T)794 static bool classof(const ProgramPointTag *T) { 795 return T->getTagKind() == &Kind; 796 } 797 generateMessage(BugReporterContext & BRC,PathSensitiveBugReport & R)798 std::optional<std::string> generateMessage(BugReporterContext &BRC, 799 PathSensitiveBugReport &R) const { 800 std::string Msg = Cb(BRC, R); 801 if (Msg.empty()) 802 return std::nullopt; 803 804 return std::move(Msg); 805 } 806 getTagDescription()807 StringRef getTagDescription() const override { 808 // TODO: Remember a few examples of generated messages 809 // and display them in the ExplodedGraph dump by 810 // returning them from this function. 811 return "Note Tag"; 812 } 813 isPrunable()814 bool isPrunable() const { return IsPrunable; } 815 816 friend class Factory; 817 friend class TagVisitor; 818 }; 819 820 } // namespace ento 821 822 } // namespace clang 823 824 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 825