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: StackHintGeneratorForSymbol(SymbolRef S,StringRef M)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 getMessageForReturn(const CallExpr * CallExpr)110 virtual std::string getMessageForReturn(const CallExpr *CallExpr) { 111 return Msg; 112 } 113 getMessageForSymbolNotFound()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 BugReport(Kind kind,const BugType & bt,StringRef desc)138 BugReport(Kind kind, const BugType &bt, StringRef desc) 139 : BugReport(kind, bt, "", desc) {} 140 BugReport(Kind K,const BugType & BT,StringRef ShortDescription,StringRef Description)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 getKind()149 Kind getKind() const { return K; } 150 getBugType()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. getDescription()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 getNotes()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. addRange(SourceRange R)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. getRanges()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. addFixItHint(const FixItHint & F)242 void addFixItHint(const FixItHint &F) { 243 Fixits.push_back(F); 244 } 245 getFixits()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: BasicBugReport(const BugType & bt,StringRef desc,PathDiagnosticLocation l)258 BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l) 259 : BugReport(Kind::Basic, bt, desc), Location(l) {} 260 classof(const BugReport * R)261 static bool classof(const BugReport *R) { 262 return R->getKind() == Kind::Basic; 263 } 264 getLocation()265 PathDiagnosticLocation getLocation() const override { 266 assert(Location.isValid()); 267 return Location; 268 } 269 getDeclWithIssue()270 const Decl *getDeclWithIssue() const override { 271 return DeclWithIssue; 272 } 273 getUniqueingLocation()274 PathDiagnosticLocation getUniqueingLocation() const override { 275 return getLocation(); 276 } 277 getUniqueingDecl()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. setDeclWithIssue(const Decl * declWithIssue)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: PathSensitiveBugReport(const BugType & bt,StringRef desc,const ExplodedNode * errorNode)371 PathSensitiveBugReport(const BugType &bt, StringRef desc, 372 const ExplodedNode *errorNode) 373 : PathSensitiveBugReport(bt, desc, desc, errorNode) {} 374 PathSensitiveBugReport(const BugType & bt,StringRef shortDesc,StringRef desc,const ExplodedNode * errorNode)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. PathSensitiveBugReport(const BugType & bt,StringRef desc,const ExplodedNode * errorNode,PathDiagnosticLocation LocationToUnique,const Decl * DeclToUnique)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 classof(const BugReport * R)400 static bool classof(const BugReport *R) { 401 return R->getKind() == Kind::PathSensitive; 402 } 403 getErrorNode()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. shouldPrunePath()408 bool shouldPrunePath() const { return !DoNotPrunePath; } 409 410 /// Disable all path pruning when generating a PathDiagnostic. disablePathPruning()411 void disablePathPruning() { DoNotPrunePath = true; } 412 413 /// Get the location on which the report should be uniqued. getUniqueingLocation()414 PathDiagnosticLocation getUniqueingLocation() const override { 415 return UniqueingLocation; 416 } 417 418 /// Get the declaration containing the uniqueing location. getUniqueingDecl()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 /// 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 /// Marks a symbolic value as interesting. Different kinds of interestingness 443 /// will be processed differently by visitors (e.g. if the tracking kind is 444 /// condition, will append "will be used as a condition" to the message). 445 void markInteresting(SVal V, bugreporter::TrackingKind TKind = 446 bugreporter::TrackingKind::Thorough); 447 void markInteresting(const LocationContext *LC); 448 449 bool isInteresting(SymbolRef sym) const; 450 bool isInteresting(const MemRegion *R) const; 451 bool isInteresting(SVal V) const; 452 bool isInteresting(const LocationContext *LC) const; 453 454 Optional<bugreporter::TrackingKind> 455 getInterestingnessKind(SymbolRef sym) const; 456 457 Optional<bugreporter::TrackingKind> 458 getInterestingnessKind(const MemRegion *R) const; 459 460 Optional<bugreporter::TrackingKind> getInterestingnessKind(SVal V) const; 461 462 /// Returns whether or not this report should be considered valid. 463 /// 464 /// Invalid reports are those that have been classified as likely false 465 /// positives after the fact. isValid()466 bool isValid() const { 467 return Invalidations.empty(); 468 } 469 470 /// Marks the current report as invalid, meaning that it is probably a false 471 /// positive and should not be reported to the user. 472 /// 473 /// The \p Tag and \p Data arguments are intended to be opaque identifiers for 474 /// this particular invalidation, where \p Tag represents the visitor 475 /// responsible for invalidation, and \p Data represents the reason this 476 /// visitor decided to invalidate the bug report. 477 /// 478 /// \sa removeInvalidation markInvalid(const void * Tag,const void * Data)479 void markInvalid(const void *Tag, const void *Data) { 480 Invalidations.insert(std::make_pair(Tag, Data)); 481 } 482 483 /// Profile to identify equivalent bug reports for error report coalescing. 484 /// Reports are uniqued to ensure that we do not emit multiple diagnostics 485 /// for each bug. 486 void Profile(llvm::FoldingSetNodeID &hash) const override; 487 488 /// Add custom or predefined bug report visitors to this report. 489 /// 490 /// The visitors should be used when the default trace is not sufficient. 491 /// For example, they allow constructing a more elaborate trace. 492 /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(), 493 /// registerFindLastStore(), registerNilReceiverVisitor(), and 494 /// registerVarDeclsLastStore(). 495 void addVisitor(std::unique_ptr<BugReporterVisitor> visitor); 496 497 /// Remove all visitors attached to this bug report. 498 void clearVisitors(); 499 500 /// Iterators through the custom diagnostic visitors. visitor_begin()501 visitor_iterator visitor_begin() { return Callbacks.begin(); } visitor_end()502 visitor_iterator visitor_end() { return Callbacks.end(); } visitors()503 visitor_range visitors() { return {visitor_begin(), visitor_end()}; } 504 505 /// Notes that the condition of the CFGBlock associated with \p Cond is 506 /// being tracked. 507 /// \returns false if the condition is already being tracked. addTrackedCondition(const ExplodedNode * Cond)508 bool addTrackedCondition(const ExplodedNode *Cond) { 509 return TrackedConditions.insert(Cond).second; 510 } 511 addCallStackHint(PathDiagnosticPieceRef Piece,std::unique_ptr<StackHintGenerator> StackHint)512 void addCallStackHint(PathDiagnosticPieceRef Piece, 513 std::unique_ptr<StackHintGenerator> StackHint) { 514 StackHints[Piece] = std::move(StackHint); 515 } 516 hasCallStackHint(PathDiagnosticPieceRef Piece)517 bool hasCallStackHint(PathDiagnosticPieceRef Piece) const { 518 return StackHints.count(Piece) > 0; 519 } 520 521 /// Produce the hint for the given node. The node contains 522 /// information about the call for which the diagnostic can be generated. 523 std::string getCallStackMessage(PathDiagnosticPieceRef Piece,const ExplodedNode * N)524 getCallStackMessage(PathDiagnosticPieceRef Piece, 525 const ExplodedNode *N) const { 526 auto I = StackHints.find(Piece); 527 if (I != StackHints.end()) 528 return I->second->getMessage(N); 529 return ""; 530 } 531 }; 532 533 //===----------------------------------------------------------------------===// 534 // BugTypes (collections of related reports). 535 //===----------------------------------------------------------------------===// 536 537 class BugReportEquivClass : public llvm::FoldingSetNode { 538 friend class BugReporter; 539 540 /// List of *owned* BugReport objects. 541 llvm::SmallVector<std::unique_ptr<BugReport>, 4> Reports; 542 AddReport(std::unique_ptr<BugReport> && R)543 void AddReport(std::unique_ptr<BugReport> &&R) { 544 Reports.push_back(std::move(R)); 545 } 546 547 public: BugReportEquivClass(std::unique_ptr<BugReport> R)548 BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); } 549 getReports()550 ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; } 551 Profile(llvm::FoldingSetNodeID & ID)552 void Profile(llvm::FoldingSetNodeID& ID) const { 553 assert(!Reports.empty()); 554 Reports.front()->Profile(ID); 555 } 556 }; 557 558 //===----------------------------------------------------------------------===// 559 // BugReporter and friends. 560 //===----------------------------------------------------------------------===// 561 562 class BugReporterData { 563 public: 564 virtual ~BugReporterData() = default; 565 566 virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; 567 virtual ASTContext &getASTContext() = 0; 568 virtual SourceManager &getSourceManager() = 0; 569 virtual AnalyzerOptions &getAnalyzerOptions() = 0; 570 virtual Preprocessor &getPreprocessor() = 0; 571 }; 572 573 /// BugReporter is a utility class for generating PathDiagnostics for analysis. 574 /// It collects the BugReports and BugTypes and knows how to generate 575 /// and flush the corresponding diagnostics. 576 /// 577 /// The base class is used for generating path-insensitive 578 class BugReporter { 579 private: 580 BugReporterData& D; 581 582 /// Generate and flush the diagnostics for the given bug report. 583 void FlushReport(BugReportEquivClass& EQ); 584 585 /// The set of bug reports tracked by the BugReporter. 586 llvm::FoldingSet<BugReportEquivClass> EQClasses; 587 588 /// A vector of BugReports for tracking the allocated pointers and cleanup. 589 std::vector<BugReportEquivClass *> EQClassesVector; 590 591 public: 592 BugReporter(BugReporterData &d); 593 virtual ~BugReporter(); 594 595 /// Generate and flush diagnostics for all bug reports. 596 void FlushReports(); 597 getPathDiagnosticConsumers()598 ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { 599 return D.getPathDiagnosticConsumers(); 600 } 601 602 /// Iterator over the set of BugReports tracked by the BugReporter. 603 using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator; EQClasses_begin()604 EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } EQClasses_end()605 EQClasses_iterator EQClasses_end() { return EQClasses.end(); } 606 getContext()607 ASTContext &getContext() { return D.getASTContext(); } 608 getSourceManager()609 const SourceManager &getSourceManager() { return D.getSourceManager(); } 610 getAnalyzerOptions()611 const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); } 612 getPreprocessor()613 Preprocessor &getPreprocessor() { return D.getPreprocessor(); } 614 615 /// Add the given report to the set of reports tracked by BugReporter. 616 /// 617 /// The reports are usually generated by the checkers. Further, they are 618 /// folded based on the profile value, which is done to coalesce similar 619 /// reports. 620 virtual void emitReport(std::unique_ptr<BugReport> R); 621 622 void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, 623 StringRef BugName, StringRef BugCategory, 624 StringRef BugStr, PathDiagnosticLocation Loc, 625 ArrayRef<SourceRange> Ranges = None, 626 ArrayRef<FixItHint> Fixits = None); 627 628 void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName, 629 StringRef BugName, StringRef BugCategory, 630 StringRef BugStr, PathDiagnosticLocation Loc, 631 ArrayRef<SourceRange> Ranges = None, 632 ArrayRef<FixItHint> Fixits = None); 633 634 private: 635 llvm::StringMap<std::unique_ptr<BugType>> StrBugTypes; 636 637 /// Returns a BugType that is associated with the given name and 638 /// category. 639 BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name, 640 StringRef category); 641 642 virtual BugReport * findReportInEquivalenceClass(BugReportEquivClass & eqClass,SmallVectorImpl<BugReport * > & bugReports)643 findReportInEquivalenceClass(BugReportEquivClass &eqClass, 644 SmallVectorImpl<BugReport *> &bugReports) { 645 return eqClass.getReports()[0].get(); 646 } 647 648 protected: 649 /// Generate the diagnostics for the given bug report. 650 virtual std::unique_ptr<DiagnosticForConsumerMapTy> 651 generateDiagnosticForConsumerMap(BugReport *exampleReport, 652 ArrayRef<PathDiagnosticConsumer *> consumers, 653 ArrayRef<BugReport *> bugReports); 654 }; 655 656 /// GRBugReporter is used for generating path-sensitive reports. 657 class PathSensitiveBugReporter final : public BugReporter { 658 ExprEngine& Eng; 659 660 BugReport *findReportInEquivalenceClass( 661 BugReportEquivClass &eqClass, 662 SmallVectorImpl<BugReport *> &bugReports) override; 663 664 /// Generate the diagnostics for the given bug report. 665 std::unique_ptr<DiagnosticForConsumerMapTy> 666 generateDiagnosticForConsumerMap(BugReport *exampleReport, 667 ArrayRef<PathDiagnosticConsumer *> consumers, 668 ArrayRef<BugReport *> bugReports) override; 669 public: PathSensitiveBugReporter(BugReporterData & d,ExprEngine & eng)670 PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng) 671 : BugReporter(d), Eng(eng) {} 672 673 /// getGraph - Get the exploded graph created by the analysis engine 674 /// for the analyzed method or function. 675 const ExplodedGraph &getGraph() const; 676 677 /// getStateManager - Return the state manager used by the analysis 678 /// engine. 679 ProgramStateManager &getStateManager() const; 680 681 /// \p bugReports A set of bug reports within a *single* equivalence class 682 /// 683 /// \return A mapping from consumers to the corresponding diagnostics. 684 /// Iterates through the bug reports within a single equivalence class, 685 /// stops at a first non-invalidated report. 686 std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics( 687 ArrayRef<PathDiagnosticConsumer *> consumers, 688 ArrayRef<PathSensitiveBugReport *> &bugReports); 689 690 void emitReport(std::unique_ptr<BugReport> R) override; 691 }; 692 693 694 class BugReporterContext { 695 PathSensitiveBugReporter &BR; 696 697 virtual void anchor(); 698 699 public: BugReporterContext(PathSensitiveBugReporter & br)700 BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {} 701 702 virtual ~BugReporterContext() = default; 703 getBugReporter()704 PathSensitiveBugReporter& getBugReporter() { return BR; } 705 getStateManager()706 ProgramStateManager& getStateManager() const { 707 return BR.getStateManager(); 708 } 709 getASTContext()710 ASTContext &getASTContext() const { 711 return BR.getContext(); 712 } 713 getSourceManager()714 const SourceManager& getSourceManager() const { 715 return BR.getSourceManager(); 716 } 717 getAnalyzerOptions()718 const AnalyzerOptions &getAnalyzerOptions() const { 719 return BR.getAnalyzerOptions(); 720 } 721 }; 722 723 724 /// The tag upon which the TagVisitor reacts. Add these in order to display 725 /// additional PathDiagnosticEventPieces along the path. 726 class NoteTag : public ProgramPointTag { 727 public: 728 using Callback = 729 std::function<std::string(BugReporterContext &, 730 PathSensitiveBugReport &)>; 731 732 private: 733 static int Kind; 734 735 const Callback Cb; 736 const bool IsPrunable; 737 NoteTag(Callback && Cb,bool IsPrunable)738 NoteTag(Callback &&Cb, bool IsPrunable) 739 : ProgramPointTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {} 740 741 public: classof(const ProgramPointTag * T)742 static bool classof(const ProgramPointTag *T) { 743 return T->getTagKind() == &Kind; 744 } 745 generateMessage(BugReporterContext & BRC,PathSensitiveBugReport & R)746 Optional<std::string> generateMessage(BugReporterContext &BRC, 747 PathSensitiveBugReport &R) const { 748 std::string Msg = Cb(BRC, R); 749 if (Msg.empty()) 750 return None; 751 752 return std::move(Msg); 753 } 754 getTagDescription()755 StringRef getTagDescription() const override { 756 // TODO: Remember a few examples of generated messages 757 // and display them in the ExplodedGraph dump by 758 // returning them from this function. 759 return "Note Tag"; 760 } 761 isPrunable()762 bool isPrunable() const { return IsPrunable; } 763 764 // Manage memory for NoteTag objects. 765 class Factory { 766 std::vector<std::unique_ptr<NoteTag>> Tags; 767 768 public: 769 const NoteTag *makeNoteTag(Callback &&Cb, bool IsPrunable = false) { 770 // We cannot use std::make_unique because we cannot access the private 771 // constructor from inside it. 772 std::unique_ptr<NoteTag> T(new NoteTag(std::move(Cb), IsPrunable)); 773 Tags.push_back(std::move(T)); 774 return Tags.back().get(); 775 } 776 }; 777 778 friend class TagVisitor; 779 }; 780 781 } // namespace ento 782 783 } // namespace clang 784 785 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 786