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