1341825Sdim//===- BugReporter.h - Generate PathDiagnostics -----------------*- C++ -*-===// 2218887Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6218887Sdim// 7218887Sdim//===----------------------------------------------------------------------===// 8218887Sdim// 9218887Sdim// This file defines BugReporter, a utility class for generating 10226633Sdim// PathDiagnostics for analyses based on ProgramState. 11218887Sdim// 12218887Sdim//===----------------------------------------------------------------------===// 13218887Sdim 14280031Sdim#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 15280031Sdim#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 16218887Sdim 17360784Sdim#include "clang/Analysis/PathDiagnostic.h" 18341825Sdim#include "clang/Basic/LLVM.h" 19218887Sdim#include "clang/Basic/SourceLocation.h" 20327952Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" 21276479Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 22226633Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 23341825Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 24341825Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" 25341825Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 26341825Sdim#include "llvm/ADT/ArrayRef.h" 27249423Sdim#include "llvm/ADT/DenseSet.h" 28218887Sdim#include "llvm/ADT/FoldingSet.h" 29249423Sdim#include "llvm/ADT/ImmutableSet.h" 30341825Sdim#include "llvm/ADT/None.h" 31249423Sdim#include "llvm/ADT/SmallSet.h" 32341825Sdim#include "llvm/ADT/SmallVector.h" 33341825Sdim#include "llvm/ADT/StringMap.h" 34341825Sdim#include "llvm/ADT/StringRef.h" 35234353Sdim#include "llvm/ADT/ilist.h" 36234353Sdim#include "llvm/ADT/ilist_node.h" 37341825Sdim#include "llvm/ADT/iterator_range.h" 38341825Sdim#include <cassert> 39341825Sdim#include <memory> 40341825Sdim#include <string> 41341825Sdim#include <utility> 42341825Sdim#include <vector> 43218887Sdim 44218887Sdimnamespace clang { 45218887Sdim 46341825Sdimclass AnalyzerOptions; 47218887Sdimclass ASTContext; 48341825Sdimclass Decl; 49226633Sdimclass DiagnosticsEngine; 50341825Sdimclass LocationContext; 51341825Sdimclass SourceManager; 52218887Sdimclass Stmt; 53218887Sdim 54218887Sdimnamespace ento { 55218887Sdim 56341825Sdimclass BugType; 57341825Sdimclass CheckerBase; 58341825Sdimclass ExplodedGraph; 59218887Sdimclass ExplodedNode; 60218887Sdimclass ExprEngine; 61341825Sdimclass MemRegion; 62341825Sdimclass SValBuilder; 63218887Sdim 64218887Sdim//===----------------------------------------------------------------------===// 65218887Sdim// Interface for individual bug reports. 66218887Sdim//===----------------------------------------------------------------------===// 67218887Sdim 68341825Sdim/// A mapping from diagnostic consumers to the diagnostics they should 69341825Sdim/// consume. 70341825Sdimusing DiagnosticForConsumerMapTy = 71341825Sdim llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>; 72341825Sdim 73360784Sdim/// Interface for classes constructing Stack hints. 74360784Sdim/// 75360784Sdim/// If a PathDiagnosticEvent occurs in a different frame than the final 76360784Sdim/// diagnostic the hints can be used to summarize the effect of the call. 77360784Sdimclass StackHintGenerator { 78341825Sdimpublic: 79360784Sdim virtual ~StackHintGenerator() = 0; 80341825Sdim 81360784Sdim /// Construct the Diagnostic message for the given ExplodedNode. 82360784Sdim virtual std::string getMessage(const ExplodedNode *N) = 0; 83360784Sdim}; 84341825Sdim 85360784Sdim/// Constructs a Stack hint for the given symbol. 86360784Sdim/// 87360784Sdim/// The class knows how to construct the stack hint message based on 88360784Sdim/// traversing the CallExpr associated with the call and checking if the given 89360784Sdim/// symbol is returned or is one of the arguments. 90360784Sdim/// The hint can be customized by redefining 'getMessageForX()' methods. 91360784Sdimclass StackHintGeneratorForSymbol : public StackHintGenerator { 92360784Sdimprivate: 93360784Sdim SymbolRef Sym; 94360784Sdim std::string Msg; 95218887Sdim 96360784Sdimpublic: 97360784Sdim StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {} 98360784Sdim ~StackHintGeneratorForSymbol() override = default; 99218887Sdim 100360784Sdim /// Search the call expression for the symbol Sym and dispatch the 101360784Sdim /// 'getMessageForX()' methods to construct a specific message. 102360784Sdim std::string getMessage(const ExplodedNode *N) override; 103360784Sdim 104360784Sdim /// Produces the message of the following form: 105360784Sdim /// 'Msg via Nth parameter' 106360784Sdim virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex); 107360784Sdim 108360784Sdim virtual std::string getMessageForReturn(const CallExpr *CallExpr) { 109360784Sdim return Msg; 110360784Sdim } 111360784Sdim 112360784Sdim virtual std::string getMessageForSymbolNotFound() { 113360784Sdim return Msg; 114360784Sdim } 115360784Sdim}; 116360784Sdim 117360784Sdim/// This class provides an interface through which checkers can create 118360784Sdim/// individual bug reports. 119360784Sdimclass BugReport { 120360784Sdimpublic: 121360784Sdim enum class Kind { Basic, PathSensitive }; 122360784Sdim 123218887Sdimprotected: 124341825Sdim friend class BugReportEquivClass; 125226633Sdim friend class BugReporter; 126226633Sdim 127360784Sdim Kind K; 128353358Sdim const BugType& BT; 129218887Sdim std::string ShortDescription; 130218887Sdim std::string Description; 131360784Sdim 132360784Sdim SmallVector<SourceRange, 4> Ranges; 133360784Sdim SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> Notes; 134360784Sdim SmallVector<FixItHint, 4> Fixits; 135360784Sdim 136360784Sdim BugReport(Kind kind, const BugType &bt, StringRef desc) 137360784Sdim : K(kind), BT(bt), Description(desc) {} 138360784Sdim 139360784Sdim BugReport(Kind K, const BugType &BT, StringRef ShortDescription, 140360784Sdim StringRef Description) 141360784Sdim : K(K), BT(BT), ShortDescription(ShortDescription), 142360784Sdim Description(Description) {} 143360784Sdim 144360784Sdimpublic: 145360784Sdim virtual ~BugReport() = default; 146360784Sdim 147360784Sdim Kind getKind() const { return K; } 148360784Sdim 149360784Sdim const BugType& getBugType() const { return BT; } 150360784Sdim 151360784Sdim /// A verbose warning message that is appropriate for displaying next to 152360784Sdim /// the source code that introduces the problem. The description should be 153360784Sdim /// at least a full sentence starting with a capital letter. The period at 154360784Sdim /// the end of the warning is traditionally omitted. If the description 155360784Sdim /// consists of multiple sentences, periods between the sentences are 156360784Sdim /// encouraged, but the period at the end of the description is still omitted. 157360784Sdim StringRef getDescription() const { return Description; } 158360784Sdim 159360784Sdim /// A short general warning message that is appropriate for displaying in 160360784Sdim /// the list of all reported bugs. It should describe what kind of bug is found 161360784Sdim /// but does not need to try to go into details of that specific bug. 162360784Sdim /// Grammatical conventions of getDescription() apply here as well. 163360784Sdim StringRef getShortDescription(bool UseFallback = true) const { 164360784Sdim if (ShortDescription.empty() && UseFallback) 165360784Sdim return Description; 166360784Sdim return ShortDescription; 167360784Sdim } 168360784Sdim 169360784Sdim /// The primary location of the bug report that points at the undesirable 170360784Sdim /// behavior in the code. UIs should attach the warning description to this 171360784Sdim /// location. The warning description should describe the bad behavior 172360784Sdim /// at this location. 173360784Sdim virtual PathDiagnosticLocation getLocation() const = 0; 174360784Sdim 175360784Sdim /// The smallest declaration that contains the bug location. 176360784Sdim /// This is purely cosmetic; the declaration can be displayed to the user 177360784Sdim /// but it does not affect whether the report is emitted. 178360784Sdim virtual const Decl *getDeclWithIssue() const = 0; 179360784Sdim 180360784Sdim /// Get the location on which the report should be uniqued. Two warnings are 181360784Sdim /// considered to be equivalent whenever they have the same bug types, 182360784Sdim /// descriptions, and uniqueing locations. Out of a class of equivalent 183360784Sdim /// warnings only one gets displayed to the user. For most warnings the 184360784Sdim /// uniqueing location coincides with their location, but sometimes 185360784Sdim /// it makes sense to use different locations. For example, a leak 186360784Sdim /// checker can place the warning at the location where the last reference 187360784Sdim /// to the leaking resource is dropped but at the same time unique the warning 188360784Sdim /// by where that resource is acquired (allocated). 189360784Sdim virtual PathDiagnosticLocation getUniqueingLocation() const = 0; 190360784Sdim 191360784Sdim /// Get the declaration that corresponds to (usually contains) the uniqueing 192360784Sdim /// location. This is not actively used for uniqueing, i.e. otherwise 193360784Sdim /// identical reports that have different uniqueing decls will be considered 194360784Sdim /// equivalent. 195360784Sdim virtual const Decl *getUniqueingDecl() const = 0; 196360784Sdim 197360784Sdim /// Add new item to the list of additional notes that need to be attached to 198360784Sdim /// this report. If the report is path-sensitive, these notes will not be 199360784Sdim /// displayed as part of the execution path explanation, but will be displayed 200360784Sdim /// separately. Use bug visitors if you need to add an extra path note. 201360784Sdim void addNote(StringRef Msg, const PathDiagnosticLocation &Pos, 202360784Sdim ArrayRef<SourceRange> Ranges = {}) { 203360784Sdim auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg); 204360784Sdim 205360784Sdim for (const auto &R : Ranges) 206360784Sdim P->addRange(R); 207360784Sdim 208360784Sdim Notes.push_back(std::move(P)); 209360784Sdim } 210360784Sdim 211360784Sdim ArrayRef<std::shared_ptr<PathDiagnosticNotePiece>> getNotes() { 212360784Sdim return Notes; 213360784Sdim } 214360784Sdim 215360784Sdim /// Add a range to a bug report. 216360784Sdim /// 217360784Sdim /// Ranges are used to highlight regions of interest in the source code. 218360784Sdim /// They should be at the same source code line as the BugReport location. 219360784Sdim /// By default, the source range of the statement corresponding to the error 220360784Sdim /// node will be used; add a single invalid range to specify absence of 221360784Sdim /// ranges. 222360784Sdim void addRange(SourceRange R) { 223360784Sdim assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used " 224360784Sdim "to specify that the report does not have a range."); 225360784Sdim Ranges.push_back(R); 226360784Sdim } 227360784Sdim 228360784Sdim /// Get the SourceRanges associated with the report. 229360784Sdim virtual ArrayRef<SourceRange> getRanges() const { 230360784Sdim return Ranges; 231360784Sdim } 232360784Sdim 233360784Sdim /// Add a fix-it hint to the bug report. 234360784Sdim /// 235360784Sdim /// Fix-it hints are the suggested edits to the code that would resolve 236360784Sdim /// the problem explained by the bug report. Fix-it hints should be 237360784Sdim /// as conservative as possible because it is not uncommon for the user 238360784Sdim /// to blindly apply all fixits to their project. Note that it is very hard 239360784Sdim /// to produce a good fix-it hint for most path-sensitive warnings. 240360784Sdim void addFixItHint(const FixItHint &F) { 241360784Sdim Fixits.push_back(F); 242360784Sdim } 243360784Sdim 244360784Sdim llvm::ArrayRef<FixItHint> getFixits() const { return Fixits; } 245360784Sdim 246360784Sdim /// Reports are uniqued to ensure that we do not emit multiple diagnostics 247360784Sdim /// for each bug. 248360784Sdim virtual void Profile(llvm::FoldingSetNodeID& hash) const = 0; 249360784Sdim}; 250360784Sdim 251360784Sdimclass BasicBugReport : public BugReport { 252226633Sdim PathDiagnosticLocation Location; 253360784Sdim const Decl *DeclWithIssue = nullptr; 254341825Sdim 255360784Sdimpublic: 256360784Sdim BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l) 257360784Sdim : BugReport(Kind::Basic, bt, desc), Location(l) {} 258360784Sdim 259360784Sdim static bool classof(const BugReport *R) { 260360784Sdim return R->getKind() == Kind::Basic; 261360784Sdim } 262360784Sdim 263360784Sdim PathDiagnosticLocation getLocation() const override { 264360784Sdim assert(Location.isValid()); 265360784Sdim return Location; 266360784Sdim } 267360784Sdim 268360784Sdim const Decl *getDeclWithIssue() const override { 269360784Sdim return DeclWithIssue; 270360784Sdim } 271360784Sdim 272360784Sdim PathDiagnosticLocation getUniqueingLocation() const override { 273360784Sdim return getLocation(); 274360784Sdim } 275360784Sdim 276360784Sdim const Decl *getUniqueingDecl() const override { 277360784Sdim return getDeclWithIssue(); 278360784Sdim } 279360784Sdim 280360784Sdim /// Specifically set the Decl where an issue occurred. This isn't necessary 281360784Sdim /// for BugReports that cover a path as it will be automatically inferred. 282360784Sdim void setDeclWithIssue(const Decl *declWithIssue) { 283360784Sdim DeclWithIssue = declWithIssue; 284360784Sdim } 285360784Sdim 286360784Sdim void Profile(llvm::FoldingSetNodeID& hash) const override; 287360784Sdim}; 288360784Sdim 289360784Sdimclass PathSensitiveBugReport : public BugReport { 290360784Sdimpublic: 291360784Sdim using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>; 292360784Sdim using visitor_iterator = VisitorList::iterator; 293360784Sdim using visitor_range = llvm::iterator_range<visitor_iterator>; 294360784Sdim 295360784Sdimprotected: 296360784Sdim /// The ExplodedGraph node against which the report was thrown. It corresponds 297360784Sdim /// to the end of the execution path that demonstrates the bug. 298341825Sdim const ExplodedNode *ErrorNode = nullptr; 299314564Sdim 300360784Sdim /// The range that corresponds to ErrorNode's program point. It is usually 301360784Sdim /// highlighted in the report. 302360784Sdim const SourceRange ErrorNodeRange; 303218887Sdim 304360784Sdim /// Profile to identify equivalent bug reports for error report coalescing. 305360784Sdim 306239462Sdim /// A (stack of) a set of symbols that are registered with this 307239462Sdim /// report as being "interesting", and thus used to help decide which 308239462Sdim /// diagnostics to include when constructing the final path diagnostic. 309239462Sdim /// The stack is largely used by BugReporter when generating PathDiagnostics 310239462Sdim /// for multiple PathDiagnosticConsumers. 311360784Sdim llvm::DenseMap<SymbolRef, bugreporter::TrackingKind> InterestingSymbols; 312234353Sdim 313239462Sdim /// A (stack of) set of regions that are registered with this report as being 314234353Sdim /// "interesting", and thus used to help decide which diagnostics 315234353Sdim /// to include when constructing the final path diagnostic. 316239462Sdim /// The stack is largely used by BugReporter when generating PathDiagnostics 317239462Sdim /// for multiple PathDiagnosticConsumers. 318360784Sdim llvm::DenseMap<const MemRegion *, bugreporter::TrackingKind> 319360784Sdim InterestingRegions; 320234353Sdim 321243830Sdim /// A set of location contexts that correspoind to call sites which should be 322243830Sdim /// considered "interesting". 323243830Sdim llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts; 324243830Sdim 325234353Sdim /// A set of custom visitors which generate "event" diagnostics at 326234353Sdim /// interesting points in the path. 327234353Sdim VisitorList Callbacks; 328234353Sdim 329234353Sdim /// Used for ensuring the visitors are only added once. 330226633Sdim llvm::FoldingSet<BugReporterVisitor> CallbacksSet; 331218887Sdim 332239462Sdim /// When set, this flag disables all callstack pruning from a diagnostic 333239462Sdim /// path. This is useful for some reports that want maximum fidelty 334239462Sdim /// when reporting an issue. 335341825Sdim bool DoNotPrunePath = false; 336234353Sdim 337243830Sdim /// Used to track unique reasons why a bug report might be invalid. 338243830Sdim /// 339243830Sdim /// \sa markInvalid 340243830Sdim /// \sa removeInvalidation 341341825Sdim using InvalidationRecord = std::pair<const void *, const void *>; 342243830Sdim 343243830Sdim /// If non-empty, this bug report is likely a false positive and should not be 344243830Sdim /// shown to the user. 345243830Sdim /// 346243830Sdim /// \sa markInvalid 347243830Sdim /// \sa removeInvalidation 348243830Sdim llvm::SmallSet<InvalidationRecord, 4> Invalidations; 349243830Sdim 350353358Sdim /// Conditions we're already tracking. 351353358Sdim llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions; 352353358Sdim 353360784Sdim /// Reports with different uniqueing locations are considered to be different 354360784Sdim /// for the purposes of deduplication. 355360784Sdim PathDiagnosticLocation UniqueingLocation; 356360784Sdim const Decl *UniqueingDecl; 357239462Sdim 358360784Sdim const Stmt *getStmt() const; 359239462Sdim 360360784Sdim /// If an event occurs in a different frame than the final diagnostic, 361360784Sdim /// supply a message that will be used to construct an extra hint on the 362360784Sdim /// returns from all the calls on the stack from this event to the final 363360784Sdim /// diagnostic. 364360784Sdim // FIXME: Allow shared_ptr keys in DenseMap? 365360784Sdim std::map<PathDiagnosticPieceRef, std::unique_ptr<StackHintGenerator>> 366360784Sdim StackHints; 367360784Sdim 368218887Sdimpublic: 369360784Sdim PathSensitiveBugReport(const BugType &bt, StringRef desc, 370360784Sdim const ExplodedNode *errorNode) 371360784Sdim : BugReport(Kind::PathSensitive, bt, desc), ErrorNode(errorNode), 372360784Sdim ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() 373360784Sdim : SourceRange()) {} 374218887Sdim 375360784Sdim PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc, 376360784Sdim const ExplodedNode *errorNode) 377360784Sdim : BugReport(Kind::PathSensitive, bt, shortDesc, desc), 378360784Sdim ErrorNode(errorNode), 379360784Sdim ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() 380360784Sdim : SourceRange()) {} 381218887Sdim 382360784Sdim /// Create a PathSensitiveBugReport with a custom uniqueing location. 383234353Sdim /// 384234353Sdim /// The reports that have the same report location, description, bug type, and 385234353Sdim /// ranges are uniqued - only one of the equivalent reports will be presented 386234353Sdim /// to the user. This method allows to rest the location which should be used 387234353Sdim /// for uniquing reports. For example, memory leaks checker, could set this to 388234353Sdim /// the allocation site, rather then the location where the bug is reported. 389360784Sdim PathSensitiveBugReport(const BugType &bt, StringRef desc, 390360784Sdim const ExplodedNode *errorNode, 391360784Sdim PathDiagnosticLocation LocationToUnique, 392360784Sdim const Decl *DeclToUnique) 393360784Sdim : BugReport(Kind::PathSensitive, bt, desc), ErrorNode(errorNode), 394360784Sdim ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() : SourceRange()), 395360784Sdim UniqueingLocation(LocationToUnique), UniqueingDecl(DeclToUnique) { 396360784Sdim assert(errorNode); 397360784Sdim } 398234353Sdim 399360784Sdim static bool classof(const BugReport *R) { 400360784Sdim return R->getKind() == Kind::PathSensitive; 401360784Sdim } 402218887Sdim 403226633Sdim const ExplodedNode *getErrorNode() const { return ErrorNode; } 404218887Sdim 405239462Sdim /// Indicates whether or not any path pruning should take place 406239462Sdim /// when generating a PathDiagnostic from this BugReport. 407239462Sdim bool shouldPrunePath() const { return !DoNotPrunePath; } 408239462Sdim 409239462Sdim /// Disable all path pruning when generating a PathDiagnostic. 410239462Sdim void disablePathPruning() { DoNotPrunePath = true; } 411341825Sdim 412360784Sdim /// Get the location on which the report should be uniqued. 413360784Sdim PathDiagnosticLocation getUniqueingLocation() const override { 414360784Sdim return UniqueingLocation; 415360784Sdim } 416360784Sdim 417360784Sdim /// Get the declaration containing the uniqueing location. 418360784Sdim const Decl *getUniqueingDecl() const override { 419360784Sdim return UniqueingDecl; 420360784Sdim } 421360784Sdim 422360784Sdim const Decl *getDeclWithIssue() const override; 423360784Sdim 424360784Sdim ArrayRef<SourceRange> getRanges() const override; 425360784Sdim 426360784Sdim PathDiagnosticLocation getLocation() const override; 427360784Sdim 428360784Sdim /// Marks a symbol as interesting. Different kinds of interestingness will 429360784Sdim /// be processed differently by visitors (e.g. if the tracking kind is 430360784Sdim /// condition, will append "will be used as a condition" to the message). 431360784Sdim void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind = 432360784Sdim bugreporter::TrackingKind::Thorough); 433360784Sdim 434360784Sdim /// Marks a region as interesting. Different kinds of interestingness will 435360784Sdim /// be processed differently by visitors (e.g. if the tracking kind is 436360784Sdim /// condition, will append "will be used as a condition" to the message). 437360784Sdim void markInteresting( 438360784Sdim const MemRegion *R, 439360784Sdim bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough); 440360784Sdim 441360784Sdim /// Marks a symbolic value as interesting. Different kinds of interestingness 442360784Sdim /// will be processed differently by visitors (e.g. if the tracking kind is 443360784Sdim /// condition, will append "will be used as a condition" to the message). 444360784Sdim void markInteresting(SVal V, bugreporter::TrackingKind TKind = 445360784Sdim bugreporter::TrackingKind::Thorough); 446243830Sdim void markInteresting(const LocationContext *LC); 447341825Sdim 448360784Sdim bool isInteresting(SymbolRef sym) const; 449360784Sdim bool isInteresting(const MemRegion *R) const; 450360784Sdim bool isInteresting(SVal V) const; 451360784Sdim bool isInteresting(const LocationContext *LC) const; 452234353Sdim 453360784Sdim Optional<bugreporter::TrackingKind> 454360784Sdim getInterestingnessKind(SymbolRef sym) const; 455360784Sdim 456360784Sdim Optional<bugreporter::TrackingKind> 457360784Sdim getInterestingnessKind(const MemRegion *R) const; 458360784Sdim 459360784Sdim Optional<bugreporter::TrackingKind> getInterestingnessKind(SVal V) const; 460360784Sdim 461243830Sdim /// Returns whether or not this report should be considered valid. 462243830Sdim /// 463243830Sdim /// Invalid reports are those that have been classified as likely false 464243830Sdim /// positives after the fact. 465243830Sdim bool isValid() const { 466243830Sdim return Invalidations.empty(); 467243830Sdim } 468243830Sdim 469243830Sdim /// Marks the current report as invalid, meaning that it is probably a false 470243830Sdim /// positive and should not be reported to the user. 471243830Sdim /// 472243830Sdim /// The \p Tag and \p Data arguments are intended to be opaque identifiers for 473243830Sdim /// this particular invalidation, where \p Tag represents the visitor 474243830Sdim /// responsible for invalidation, and \p Data represents the reason this 475243830Sdim /// visitor decided to invalidate the bug report. 476243830Sdim /// 477243830Sdim /// \sa removeInvalidation 478243830Sdim void markInvalid(const void *Tag, const void *Data) { 479243830Sdim Invalidations.insert(std::make_pair(Tag, Data)); 480243830Sdim } 481243830Sdim 482360784Sdim /// Profile to identify equivalent bug reports for error report coalescing. 483360784Sdim /// Reports are uniqued to ensure that we do not emit multiple diagnostics 484360784Sdim /// for each bug. 485360784Sdim void Profile(llvm::FoldingSetNodeID &hash) const override; 486341825Sdim 487341825Sdim /// Add custom or predefined bug report visitors to this report. 488226633Sdim /// 489226633Sdim /// The visitors should be used when the default trace is not sufficient. 490226633Sdim /// For example, they allow constructing a more elaborate trace. 491226633Sdim /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(), 492226633Sdim /// registerFindLastStore(), registerNilReceiverVisitor(), and 493226633Sdim /// registerVarDeclsLastStore(). 494280031Sdim void addVisitor(std::unique_ptr<BugReporterVisitor> visitor); 495226633Sdim 496341825Sdim /// Remove all visitors attached to this bug report. 497341825Sdim void clearVisitors(); 498341825Sdim 499280031Sdim /// Iterators through the custom diagnostic visitors. 500226633Sdim visitor_iterator visitor_begin() { return Callbacks.begin(); } 501226633Sdim visitor_iterator visitor_end() { return Callbacks.end(); } 502360784Sdim visitor_range visitors() { return {visitor_begin(), visitor_end()}; } 503226633Sdim 504353358Sdim /// Notes that the condition of the CFGBlock associated with \p Cond is 505353358Sdim /// being tracked. 506353358Sdim /// \returns false if the condition is already being tracked. 507353358Sdim bool addTrackedCondition(const ExplodedNode *Cond) { 508353358Sdim return TrackedConditions.insert(Cond).second; 509353358Sdim } 510353358Sdim 511360784Sdim void addCallStackHint(PathDiagnosticPieceRef Piece, 512360784Sdim std::unique_ptr<StackHintGenerator> StackHint) { 513360784Sdim StackHints[Piece] = std::move(StackHint); 514360784Sdim } 515360784Sdim 516360784Sdim bool hasCallStackHint(PathDiagnosticPieceRef Piece) const { 517360784Sdim return StackHints.count(Piece) > 0; 518360784Sdim } 519360784Sdim 520360784Sdim /// Produce the hint for the given node. The node contains 521360784Sdim /// information about the call for which the diagnostic can be generated. 522360784Sdim std::string 523360784Sdim getCallStackMessage(PathDiagnosticPieceRef Piece, 524360784Sdim const ExplodedNode *N) const { 525360784Sdim auto I = StackHints.find(Piece); 526360784Sdim if (I != StackHints.end()) 527360784Sdim return I->second->getMessage(N); 528360784Sdim return ""; 529360784Sdim } 530218887Sdim}; 531218887Sdim 532218887Sdim//===----------------------------------------------------------------------===// 533218887Sdim// BugTypes (collections of related reports). 534218887Sdim//===----------------------------------------------------------------------===// 535218887Sdim 536218887Sdimclass BugReportEquivClass : public llvm::FoldingSetNode { 537341825Sdim friend class BugReporter; 538341825Sdim 539226633Sdim /// List of *owned* BugReport objects. 540360784Sdim llvm::SmallVector<std::unique_ptr<BugReport>, 4> Reports; 541218887Sdim 542360784Sdim void AddReport(std::unique_ptr<BugReport> &&R) { 543360784Sdim Reports.push_back(std::move(R)); 544280031Sdim } 545280031Sdim 546218887Sdimpublic: 547280031Sdim BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); } 548218887Sdim 549360784Sdim ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; } 550360784Sdim 551218887Sdim void Profile(llvm::FoldingSetNodeID& ID) const { 552218887Sdim assert(!Reports.empty()); 553360784Sdim Reports.front()->Profile(ID); 554218887Sdim } 555218887Sdim}; 556218887Sdim 557218887Sdim//===----------------------------------------------------------------------===// 558218887Sdim// BugReporter and friends. 559218887Sdim//===----------------------------------------------------------------------===// 560218887Sdim 561218887Sdimclass BugReporterData { 562218887Sdimpublic: 563360784Sdim virtual ~BugReporterData() = default; 564341825Sdim 565239462Sdim virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; 566226633Sdim virtual ASTContext &getASTContext() = 0; 567341825Sdim virtual SourceManager &getSourceManager() = 0; 568341825Sdim virtual AnalyzerOptions &getAnalyzerOptions() = 0; 569218887Sdim}; 570218887Sdim 571226633Sdim/// BugReporter is a utility class for generating PathDiagnostics for analysis. 572226633Sdim/// It collects the BugReports and BugTypes and knows how to generate 573226633Sdim/// and flush the corresponding diagnostics. 574341825Sdim/// 575341825Sdim/// The base class is used for generating path-insensitive 576218887Sdimclass BugReporter { 577218887Sdimprivate: 578218887Sdim BugReporterData& D; 579218887Sdim 580226633Sdim /// Generate and flush the diagnostics for the given bug report. 581218887Sdim void FlushReport(BugReportEquivClass& EQ); 582218887Sdim 583226633Sdim /// The set of bug reports tracked by the BugReporter. 584219077Sdim llvm::FoldingSet<BugReportEquivClass> EQClasses; 585341825Sdim 586226633Sdim /// A vector of BugReports for tracking the allocated pointers and cleanup. 587226633Sdim std::vector<BugReportEquivClass *> EQClassesVector; 588219077Sdim 589218887Sdimpublic: 590360784Sdim BugReporter(BugReporterData &d) : D(d) {} 591218887Sdim virtual ~BugReporter(); 592218887Sdim 593341825Sdim /// Generate and flush diagnostics for all bug reports. 594218887Sdim void FlushReports(); 595218887Sdim 596239462Sdim ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { 597239462Sdim return D.getPathDiagnosticConsumers(); 598218887Sdim } 599218887Sdim 600341825Sdim /// Iterator over the set of BugReports tracked by the BugReporter. 601341825Sdim using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator; 602219077Sdim EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } 603219077Sdim EQClasses_iterator EQClasses_end() { return EQClasses.end(); } 604219077Sdim 605226633Sdim ASTContext &getContext() { return D.getASTContext(); } 606218887Sdim 607360784Sdim const SourceManager &getSourceManager() { return D.getSourceManager(); } 608218887Sdim 609360784Sdim const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); } 610261991Sdim 611341825Sdim /// Add the given report to the set of reports tracked by BugReporter. 612226633Sdim /// 613226633Sdim /// The reports are usually generated by the checkers. Further, they are 614226633Sdim /// folded based on the profile value, which is done to coalesce similar 615226633Sdim /// reports. 616360784Sdim virtual void emitReport(std::unique_ptr<BugReport> R); 617218887Sdim 618276479Sdim void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, 619234353Sdim StringRef BugName, StringRef BugCategory, 620226633Sdim StringRef BugStr, PathDiagnosticLocation Loc, 621360784Sdim ArrayRef<SourceRange> Ranges = None, 622360784Sdim ArrayRef<FixItHint> Fixits = None); 623218887Sdim 624360784Sdim void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName, 625276479Sdim StringRef BugName, StringRef BugCategory, 626276479Sdim StringRef BugStr, PathDiagnosticLocation Loc, 627360784Sdim ArrayRef<SourceRange> Ranges = None, 628360784Sdim ArrayRef<FixItHint> Fixits = None); 629276479Sdim 630219077Sdimprivate: 631219077Sdim llvm::StringMap<BugType *> StrBugTypes; 632219077Sdim 633341825Sdim /// Returns a BugType that is associated with the given name and 634219077Sdim /// category. 635360784Sdim BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name, 636276479Sdim StringRef category); 637360784Sdim 638360784Sdim virtual BugReport * 639360784Sdim findReportInEquivalenceClass(BugReportEquivClass &eqClass, 640360784Sdim SmallVectorImpl<BugReport *> &bugReports) { 641360784Sdim return eqClass.getReports()[0].get(); 642360784Sdim } 643360784Sdim 644360784Sdimprotected: 645360784Sdim /// Generate the diagnostics for the given bug report. 646360784Sdim virtual std::unique_ptr<DiagnosticForConsumerMapTy> 647360784Sdim generateDiagnosticForConsumerMap(BugReport *exampleReport, 648360784Sdim ArrayRef<PathDiagnosticConsumer *> consumers, 649360784Sdim ArrayRef<BugReport *> bugReports); 650218887Sdim}; 651218887Sdim 652341825Sdim/// GRBugReporter is used for generating path-sensitive reports. 653360784Sdimclass PathSensitiveBugReporter final : public BugReporter { 654218887Sdim ExprEngine& Eng; 655341825Sdim 656360784Sdim BugReport *findReportInEquivalenceClass( 657360784Sdim BugReportEquivClass &eqClass, 658360784Sdim SmallVectorImpl<BugReport *> &bugReports) override; 659360784Sdim 660360784Sdim /// Generate the diagnostics for the given bug report. 661360784Sdim std::unique_ptr<DiagnosticForConsumerMapTy> 662360784Sdim generateDiagnosticForConsumerMap(BugReport *exampleReport, 663360784Sdim ArrayRef<PathDiagnosticConsumer *> consumers, 664360784Sdim ArrayRef<BugReport *> bugReports) override; 665218887Sdimpublic: 666360784Sdim PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng) 667360784Sdim : BugReporter(d), Eng(eng) {} 668218887Sdim 669218887Sdim /// getGraph - Get the exploded graph created by the analysis engine 670218887Sdim /// for the analyzed method or function. 671360784Sdim const ExplodedGraph &getGraph() const; 672218887Sdim 673218887Sdim /// getStateManager - Return the state manager used by the analysis 674218887Sdim /// engine. 675360784Sdim ProgramStateManager &getStateManager() const; 676218887Sdim 677341825Sdim /// \p bugReports A set of bug reports within a *single* equivalence class 678243830Sdim /// 679341825Sdim /// \return A mapping from consumers to the corresponding diagnostics. 680341825Sdim /// Iterates through the bug reports within a single equivalence class, 681341825Sdim /// stops at a first non-invalidated report. 682360784Sdim std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics( 683360784Sdim ArrayRef<PathDiagnosticConsumer *> consumers, 684360784Sdim ArrayRef<PathSensitiveBugReport *> &bugReports); 685218887Sdim 686360784Sdim void emitReport(std::unique_ptr<BugReport> R) override; 687218887Sdim}; 688218887Sdim 689341825Sdim 690218887Sdimclass BugReporterContext { 691360784Sdim PathSensitiveBugReporter &BR; 692341825Sdim 693234353Sdim virtual void anchor(); 694341825Sdim 695218887Sdimpublic: 696360784Sdim BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {} 697218887Sdim 698341825Sdim virtual ~BugReporterContext() = default; 699218887Sdim 700360784Sdim PathSensitiveBugReporter& getBugReporter() { return BR; } 701218887Sdim 702360784Sdim ProgramStateManager& getStateManager() const { 703218887Sdim return BR.getStateManager(); 704218887Sdim } 705218887Sdim 706360784Sdim ASTContext &getASTContext() const { 707218887Sdim return BR.getContext(); 708218887Sdim } 709218887Sdim 710360784Sdim const SourceManager& getSourceManager() const { 711218887Sdim return BR.getSourceManager(); 712218887Sdim } 713218887Sdim 714360784Sdim const AnalyzerOptions &getAnalyzerOptions() const { 715341825Sdim return BR.getAnalyzerOptions(); 716341825Sdim } 717218887Sdim}; 718218887Sdim 719353358Sdim 720353358Sdim/// The tag upon which the TagVisitor reacts. Add these in order to display 721353358Sdim/// additional PathDiagnosticEventPieces along the path. 722353358Sdimclass NoteTag : public ProgramPointTag { 723353358Sdimpublic: 724353358Sdim using Callback = 725353358Sdim std::function<std::string(BugReporterContext &, BugReport &)>; 726353358Sdim 727353358Sdimprivate: 728353358Sdim static int Kind; 729353358Sdim 730353358Sdim const Callback Cb; 731353358Sdim const bool IsPrunable; 732353358Sdim 733353358Sdim NoteTag(Callback &&Cb, bool IsPrunable) 734353358Sdim : ProgramPointTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {} 735353358Sdim 736353358Sdimpublic: 737353358Sdim static bool classof(const ProgramPointTag *T) { 738353358Sdim return T->getTagKind() == &Kind; 739353358Sdim } 740353358Sdim 741353358Sdim Optional<std::string> generateMessage(BugReporterContext &BRC, 742353358Sdim BugReport &R) const { 743353358Sdim std::string Msg = Cb(BRC, R); 744353358Sdim if (Msg.empty()) 745353358Sdim return None; 746353358Sdim 747353358Sdim return std::move(Msg); 748353358Sdim } 749353358Sdim 750353358Sdim StringRef getTagDescription() const override { 751353358Sdim // TODO: Remember a few examples of generated messages 752353358Sdim // and display them in the ExplodedGraph dump by 753353358Sdim // returning them from this function. 754353358Sdim return "Note Tag"; 755353358Sdim } 756353358Sdim 757353358Sdim bool isPrunable() const { return IsPrunable; } 758353358Sdim 759353358Sdim // Manage memory for NoteTag objects. 760353358Sdim class Factory { 761353358Sdim std::vector<std::unique_ptr<NoteTag>> Tags; 762353358Sdim 763353358Sdim public: 764353358Sdim const NoteTag *makeNoteTag(Callback &&Cb, bool IsPrunable = false) { 765360784Sdim // We cannot use std::make_unique because we cannot access the private 766353358Sdim // constructor from inside it. 767353358Sdim std::unique_ptr<NoteTag> T(new NoteTag(std::move(Cb), IsPrunable)); 768353358Sdim Tags.push_back(std::move(T)); 769353358Sdim return Tags.back().get(); 770353358Sdim } 771353358Sdim }; 772353358Sdim 773353358Sdim friend class TagVisitor; 774353358Sdim}; 775353358Sdim 776341825Sdim} // namespace ento 777218887Sdim 778341825Sdim} // namespace clang 779218887Sdim 780341825Sdim#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 781