10b57cec5SDimitry Andric //===- BugReporter.h - Generate PathDiagnostics -----------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines BugReporter, a utility class for generating
100b57cec5SDimitry Andric //  PathDiagnostics for analyses based on ProgramState.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
150b57cec5SDimitry Andric #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
160b57cec5SDimitry Andric 
17a7dea167SDimitry Andric #include "clang/Analysis/PathDiagnostic.h"
180b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
190b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
205ffd83dbSDimitry Andric #include "clang/Lex/Preprocessor.h"
210b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
225f757f3fSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h"
235ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
240b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
255ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
260b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
270b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
280b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
290b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
300b57cec5SDimitry Andric #include "llvm/ADT/FoldingSet.h"
310b57cec5SDimitry Andric #include "llvm/ADT/ImmutableSet.h"
320b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
330b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
340b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
350b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
360b57cec5SDimitry Andric #include "llvm/ADT/ilist.h"
370b57cec5SDimitry Andric #include "llvm/ADT/ilist_node.h"
380b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h"
390b57cec5SDimitry Andric #include <cassert>
400b57cec5SDimitry Andric #include <memory>
41bdd1243dSDimitry Andric #include <optional>
420b57cec5SDimitry Andric #include <string>
430b57cec5SDimitry Andric #include <utility>
440b57cec5SDimitry Andric #include <vector>
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric namespace clang {
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric class AnalyzerOptions;
490b57cec5SDimitry Andric class ASTContext;
500b57cec5SDimitry Andric class Decl;
510b57cec5SDimitry Andric class LocationContext;
520b57cec5SDimitry Andric class SourceManager;
530b57cec5SDimitry Andric class Stmt;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric namespace ento {
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric class BugType;
580b57cec5SDimitry Andric class CheckerBase;
590b57cec5SDimitry Andric class ExplodedGraph;
600b57cec5SDimitry Andric class ExplodedNode;
610b57cec5SDimitry Andric class ExprEngine;
620b57cec5SDimitry Andric class MemRegion;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
650b57cec5SDimitry Andric // Interface for individual bug reports.
660b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric /// A mapping from diagnostic consumers to the diagnostics they should
690b57cec5SDimitry Andric /// consume.
700b57cec5SDimitry Andric using DiagnosticForConsumerMapTy =
710b57cec5SDimitry Andric     llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>;
720b57cec5SDimitry Andric 
73a7dea167SDimitry Andric /// Interface for classes constructing Stack hints.
74a7dea167SDimitry Andric ///
75a7dea167SDimitry Andric /// If a PathDiagnosticEvent occurs in a different frame than the final
76a7dea167SDimitry Andric /// diagnostic the hints can be used to summarize the effect of the call.
77a7dea167SDimitry Andric class StackHintGenerator {
780b57cec5SDimitry Andric public:
79a7dea167SDimitry Andric   virtual ~StackHintGenerator() = 0;
800b57cec5SDimitry Andric 
81a7dea167SDimitry Andric   /// Construct the Diagnostic message for the given ExplodedNode.
82a7dea167SDimitry Andric   virtual std::string getMessage(const ExplodedNode *N) = 0;
830b57cec5SDimitry Andric };
840b57cec5SDimitry Andric 
85a7dea167SDimitry Andric /// Constructs a Stack hint for the given symbol.
86a7dea167SDimitry Andric ///
87a7dea167SDimitry Andric /// The class knows how to construct the stack hint message based on
88a7dea167SDimitry Andric /// traversing the CallExpr associated with the call and checking if the given
89a7dea167SDimitry Andric /// symbol is returned or is one of the arguments.
90a7dea167SDimitry Andric /// The hint can be customized by redefining 'getMessageForX()' methods.
91a7dea167SDimitry Andric class StackHintGeneratorForSymbol : public StackHintGenerator {
92a7dea167SDimitry Andric private:
93a7dea167SDimitry Andric   SymbolRef Sym;
94a7dea167SDimitry Andric   std::string Msg;
95a7dea167SDimitry Andric 
96a7dea167SDimitry Andric public:
StackHintGeneratorForSymbol(SymbolRef S,StringRef M)97a7dea167SDimitry Andric   StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
98a7dea167SDimitry Andric   ~StackHintGeneratorForSymbol() override = default;
99a7dea167SDimitry Andric 
100a7dea167SDimitry Andric   /// Search the call expression for the symbol Sym and dispatch the
101a7dea167SDimitry Andric   /// 'getMessageForX()' methods to construct a specific message.
102a7dea167SDimitry Andric   std::string getMessage(const ExplodedNode *N) override;
103a7dea167SDimitry Andric 
104a7dea167SDimitry Andric   /// Produces the message of the following form:
105a7dea167SDimitry Andric   ///   'Msg via Nth parameter'
106a7dea167SDimitry Andric   virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
107a7dea167SDimitry Andric 
getMessageForReturn(const CallExpr * CallExpr)108a7dea167SDimitry Andric   virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
109a7dea167SDimitry Andric     return Msg;
110a7dea167SDimitry Andric   }
111a7dea167SDimitry Andric 
getMessageForSymbolNotFound()112a7dea167SDimitry Andric   virtual std::string getMessageForSymbolNotFound() {
113a7dea167SDimitry Andric     return Msg;
114a7dea167SDimitry Andric   }
115a7dea167SDimitry Andric };
116a7dea167SDimitry Andric 
117a7dea167SDimitry Andric /// This class provides an interface through which checkers can create
118a7dea167SDimitry Andric /// individual bug reports.
119a7dea167SDimitry Andric class BugReport {
120a7dea167SDimitry Andric public:
121a7dea167SDimitry Andric   enum class Kind { Basic, PathSensitive };
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric protected:
1240b57cec5SDimitry Andric   friend class BugReportEquivClass;
1250b57cec5SDimitry Andric   friend class BugReporter;
1260b57cec5SDimitry Andric 
127a7dea167SDimitry Andric   Kind K;
1280b57cec5SDimitry Andric   const BugType& BT;
1290b57cec5SDimitry Andric   std::string ShortDescription;
1300b57cec5SDimitry Andric   std::string Description;
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   SmallVector<SourceRange, 4> Ranges;
133a7dea167SDimitry Andric   SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> Notes;
134a7dea167SDimitry Andric   SmallVector<FixItHint, 4> Fixits;
1350b57cec5SDimitry Andric 
BugReport(Kind kind,const BugType & bt,StringRef desc)136a7dea167SDimitry Andric   BugReport(Kind kind, const BugType &bt, StringRef desc)
1375ffd83dbSDimitry Andric       : BugReport(kind, bt, "", desc) {}
138a7dea167SDimitry Andric 
BugReport(Kind K,const BugType & BT,StringRef ShortDescription,StringRef Description)139a7dea167SDimitry Andric   BugReport(Kind K, const BugType &BT, StringRef ShortDescription,
140a7dea167SDimitry Andric             StringRef Description)
141a7dea167SDimitry Andric       : K(K), BT(BT), ShortDescription(ShortDescription),
142a7dea167SDimitry Andric         Description(Description) {}
143a7dea167SDimitry Andric 
144a7dea167SDimitry Andric public:
145a7dea167SDimitry Andric   virtual ~BugReport() = default;
146a7dea167SDimitry Andric 
getKind()147a7dea167SDimitry Andric   Kind getKind() const { return K; }
148a7dea167SDimitry Andric 
getBugType()149a7dea167SDimitry Andric   const BugType& getBugType() const { return BT; }
150a7dea167SDimitry Andric 
151a7dea167SDimitry Andric   /// A verbose warning message that is appropriate for displaying next to
152a7dea167SDimitry Andric   /// the source code that introduces the problem. The description should be
153a7dea167SDimitry Andric   /// at least a full sentence starting with a capital letter. The period at
154a7dea167SDimitry Andric   /// the end of the warning is traditionally omitted. If the description
155a7dea167SDimitry Andric   /// consists of multiple sentences, periods between the sentences are
156a7dea167SDimitry Andric   /// encouraged, but the period at the end of the description is still omitted.
getDescription()157a7dea167SDimitry Andric   StringRef getDescription() const { return Description; }
158a7dea167SDimitry Andric 
159a7dea167SDimitry Andric   /// A short general warning message that is appropriate for displaying in
160a7dea167SDimitry Andric   /// the list of all reported bugs. It should describe what kind of bug is found
161a7dea167SDimitry Andric   /// but does not need to try to go into details of that specific bug.
162a7dea167SDimitry Andric   /// Grammatical conventions of getDescription() apply here as well.
163a7dea167SDimitry Andric   StringRef getShortDescription(bool UseFallback = true) const {
164a7dea167SDimitry Andric     if (ShortDescription.empty() && UseFallback)
165a7dea167SDimitry Andric       return Description;
166a7dea167SDimitry Andric     return ShortDescription;
167a7dea167SDimitry Andric   }
168a7dea167SDimitry Andric 
169a7dea167SDimitry Andric   /// The primary location of the bug report that points at the undesirable
170a7dea167SDimitry Andric   /// behavior in the code. UIs should attach the warning description to this
171a7dea167SDimitry Andric   /// location. The warning description should describe the bad behavior
172a7dea167SDimitry Andric   /// at this location.
173a7dea167SDimitry Andric   virtual PathDiagnosticLocation getLocation() const = 0;
174a7dea167SDimitry Andric 
175a7dea167SDimitry Andric   /// The smallest declaration that contains the bug location.
176a7dea167SDimitry Andric   /// This is purely cosmetic; the declaration can be displayed to the user
177a7dea167SDimitry Andric   /// but it does not affect whether the report is emitted.
178a7dea167SDimitry Andric   virtual const Decl *getDeclWithIssue() const = 0;
179a7dea167SDimitry Andric 
180a7dea167SDimitry Andric   /// Get the location on which the report should be uniqued. Two warnings are
181a7dea167SDimitry Andric   /// considered to be equivalent whenever they have the same bug types,
182a7dea167SDimitry Andric   /// descriptions, and uniqueing locations. Out of a class of equivalent
183a7dea167SDimitry Andric   /// warnings only one gets displayed to the user. For most warnings the
184a7dea167SDimitry Andric   /// uniqueing location coincides with their location, but sometimes
185a7dea167SDimitry Andric   /// it makes sense to use different locations. For example, a leak
186a7dea167SDimitry Andric   /// checker can place the warning at the location where the last reference
187a7dea167SDimitry Andric   /// to the leaking resource is dropped but at the same time unique the warning
188a7dea167SDimitry Andric   /// by where that resource is acquired (allocated).
189a7dea167SDimitry Andric   virtual PathDiagnosticLocation getUniqueingLocation() const = 0;
190a7dea167SDimitry Andric 
191a7dea167SDimitry Andric   /// Get the declaration that corresponds to (usually contains) the uniqueing
192a7dea167SDimitry Andric   /// location. This is not actively used for uniqueing, i.e. otherwise
193a7dea167SDimitry Andric   /// identical reports that have different uniqueing decls will be considered
194a7dea167SDimitry Andric   /// equivalent.
195a7dea167SDimitry Andric   virtual const Decl *getUniqueingDecl() const = 0;
196a7dea167SDimitry Andric 
197a7dea167SDimitry Andric   /// Add new item to the list of additional notes that need to be attached to
198a7dea167SDimitry Andric   /// this report. If the report is path-sensitive, these notes will not be
199a7dea167SDimitry Andric   /// displayed as part of the execution path explanation, but will be displayed
200a7dea167SDimitry Andric   /// separately. Use bug visitors if you need to add an extra path note.
201a7dea167SDimitry Andric   void addNote(StringRef Msg, const PathDiagnosticLocation &Pos,
202a7dea167SDimitry Andric                ArrayRef<SourceRange> Ranges = {}) {
203a7dea167SDimitry Andric     auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg);
204a7dea167SDimitry Andric 
205a7dea167SDimitry Andric     for (const auto &R : Ranges)
206a7dea167SDimitry Andric       P->addRange(R);
207a7dea167SDimitry Andric 
208a7dea167SDimitry Andric     Notes.push_back(std::move(P));
209a7dea167SDimitry Andric   }
210a7dea167SDimitry Andric 
getNotes()211a7dea167SDimitry Andric   ArrayRef<std::shared_ptr<PathDiagnosticNotePiece>> getNotes() {
212a7dea167SDimitry Andric     return Notes;
213a7dea167SDimitry Andric   }
214a7dea167SDimitry Andric 
215a7dea167SDimitry Andric   /// Add a range to a bug report.
216a7dea167SDimitry Andric   ///
217a7dea167SDimitry Andric   /// Ranges are used to highlight regions of interest in the source code.
218a7dea167SDimitry Andric   /// They should be at the same source code line as the BugReport location.
219a7dea167SDimitry Andric   /// By default, the source range of the statement corresponding to the error
220a7dea167SDimitry Andric   /// node will be used; add a single invalid range to specify absence of
221a7dea167SDimitry Andric   /// ranges.
addRange(SourceRange R)222a7dea167SDimitry Andric   void addRange(SourceRange R) {
223a7dea167SDimitry Andric     assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
224a7dea167SDimitry Andric                            "to specify that the report does not have a range.");
225a7dea167SDimitry Andric     Ranges.push_back(R);
226a7dea167SDimitry Andric   }
227a7dea167SDimitry Andric 
228a7dea167SDimitry Andric   /// Get the SourceRanges associated with the report.
getRanges()229a7dea167SDimitry Andric   virtual ArrayRef<SourceRange> getRanges() const {
230a7dea167SDimitry Andric     return Ranges;
231a7dea167SDimitry Andric   }
232a7dea167SDimitry Andric 
233a7dea167SDimitry Andric   /// Add a fix-it hint to the bug report.
234a7dea167SDimitry Andric   ///
235a7dea167SDimitry Andric   /// Fix-it hints are the suggested edits to the code that would resolve
236a7dea167SDimitry Andric   /// the problem explained by the bug report. Fix-it hints should be
237a7dea167SDimitry Andric   /// as conservative as possible because it is not uncommon for the user
238a7dea167SDimitry Andric   /// to blindly apply all fixits to their project. Note that it is very hard
239a7dea167SDimitry Andric   /// to produce a good fix-it hint for most path-sensitive warnings.
addFixItHint(const FixItHint & F)240a7dea167SDimitry Andric   void addFixItHint(const FixItHint &F) {
241a7dea167SDimitry Andric     Fixits.push_back(F);
242a7dea167SDimitry Andric   }
243a7dea167SDimitry Andric 
getFixits()244a7dea167SDimitry Andric   llvm::ArrayRef<FixItHint> getFixits() const { return Fixits; }
245a7dea167SDimitry Andric 
246a7dea167SDimitry Andric   /// Reports are uniqued to ensure that we do not emit multiple diagnostics
247a7dea167SDimitry Andric   /// for each bug.
248a7dea167SDimitry Andric   virtual void Profile(llvm::FoldingSetNodeID& hash) const = 0;
249a7dea167SDimitry Andric };
250a7dea167SDimitry Andric 
251a7dea167SDimitry Andric class BasicBugReport : public BugReport {
252a7dea167SDimitry Andric   PathDiagnosticLocation Location;
253a7dea167SDimitry Andric   const Decl *DeclWithIssue = nullptr;
254a7dea167SDimitry Andric 
255a7dea167SDimitry Andric public:
BasicBugReport(const BugType & bt,StringRef desc,PathDiagnosticLocation l)256a7dea167SDimitry Andric   BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l)
257a7dea167SDimitry Andric       : BugReport(Kind::Basic, bt, desc), Location(l) {}
258a7dea167SDimitry Andric 
classof(const BugReport * R)259a7dea167SDimitry Andric   static bool classof(const BugReport *R) {
260a7dea167SDimitry Andric     return R->getKind() == Kind::Basic;
261a7dea167SDimitry Andric   }
262a7dea167SDimitry Andric 
getLocation()263a7dea167SDimitry Andric   PathDiagnosticLocation getLocation() const override {
264a7dea167SDimitry Andric     assert(Location.isValid());
265a7dea167SDimitry Andric     return Location;
266a7dea167SDimitry Andric   }
267a7dea167SDimitry Andric 
getDeclWithIssue()268a7dea167SDimitry Andric   const Decl *getDeclWithIssue() const override {
269a7dea167SDimitry Andric     return DeclWithIssue;
270a7dea167SDimitry Andric   }
271a7dea167SDimitry Andric 
getUniqueingLocation()272a7dea167SDimitry Andric   PathDiagnosticLocation getUniqueingLocation() const override {
273a7dea167SDimitry Andric     return getLocation();
274a7dea167SDimitry Andric   }
275a7dea167SDimitry Andric 
getUniqueingDecl()276a7dea167SDimitry Andric   const Decl *getUniqueingDecl() const override {
277a7dea167SDimitry Andric     return getDeclWithIssue();
278a7dea167SDimitry Andric   }
279a7dea167SDimitry Andric 
280a7dea167SDimitry Andric   /// Specifically set the Decl where an issue occurred. This isn't necessary
281a7dea167SDimitry Andric   /// for BugReports that cover a path as it will be automatically inferred.
setDeclWithIssue(const Decl * declWithIssue)282a7dea167SDimitry Andric   void setDeclWithIssue(const Decl *declWithIssue) {
283a7dea167SDimitry Andric     DeclWithIssue = declWithIssue;
284a7dea167SDimitry Andric   }
285a7dea167SDimitry Andric 
286a7dea167SDimitry Andric   void Profile(llvm::FoldingSetNodeID& hash) const override;
287a7dea167SDimitry Andric };
288a7dea167SDimitry Andric 
289a7dea167SDimitry Andric class PathSensitiveBugReport : public BugReport {
290a7dea167SDimitry Andric public:
291a7dea167SDimitry Andric   using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>;
292a7dea167SDimitry Andric   using visitor_iterator = VisitorList::iterator;
293a7dea167SDimitry Andric   using visitor_range = llvm::iterator_range<visitor_iterator>;
294a7dea167SDimitry Andric 
295a7dea167SDimitry Andric protected:
296a7dea167SDimitry Andric   /// The ExplodedGraph node against which the report was thrown. It corresponds
297a7dea167SDimitry Andric   /// to the end of the execution path that demonstrates the bug.
298a7dea167SDimitry Andric   const ExplodedNode *ErrorNode = nullptr;
299a7dea167SDimitry Andric 
300a7dea167SDimitry Andric   /// The range that corresponds to ErrorNode's program point. It is usually
301a7dea167SDimitry Andric   /// highlighted in the report.
302a7dea167SDimitry Andric   const SourceRange ErrorNodeRange;
303a7dea167SDimitry Andric 
304a7dea167SDimitry Andric   /// Profile to identify equivalent bug reports for error report coalescing.
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric   /// A (stack of) a set of symbols that are registered with this
3070b57cec5SDimitry Andric   /// report as being "interesting", and thus used to help decide which
3080b57cec5SDimitry Andric   /// diagnostics to include when constructing the final path diagnostic.
3090b57cec5SDimitry Andric   /// The stack is largely used by BugReporter when generating PathDiagnostics
3100b57cec5SDimitry Andric   /// for multiple PathDiagnosticConsumers.
311a7dea167SDimitry Andric   llvm::DenseMap<SymbolRef, bugreporter::TrackingKind> InterestingSymbols;
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   /// A (stack of) set of regions that are registered with this report as being
3140b57cec5SDimitry Andric   /// "interesting", and thus used to help decide which diagnostics
3150b57cec5SDimitry Andric   /// to include when constructing the final path diagnostic.
3160b57cec5SDimitry Andric   /// The stack is largely used by BugReporter when generating PathDiagnostics
3170b57cec5SDimitry Andric   /// for multiple PathDiagnosticConsumers.
318a7dea167SDimitry Andric   llvm::DenseMap<const MemRegion *, bugreporter::TrackingKind>
319a7dea167SDimitry Andric       InterestingRegions;
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   /// A set of location contexts that correspoind to call sites which should be
3220b57cec5SDimitry Andric   /// considered "interesting".
3230b57cec5SDimitry Andric   llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts;
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric   /// A set of custom visitors which generate "event" diagnostics at
3260b57cec5SDimitry Andric   /// interesting points in the path.
3270b57cec5SDimitry Andric   VisitorList Callbacks;
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   /// Used for ensuring the visitors are only added once.
3300b57cec5SDimitry Andric   llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric   /// When set, this flag disables all callstack pruning from a diagnostic
3330b57cec5SDimitry Andric   /// path.  This is useful for some reports that want maximum fidelty
3340b57cec5SDimitry Andric   /// when reporting an issue.
3350b57cec5SDimitry Andric   bool DoNotPrunePath = false;
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   /// Used to track unique reasons why a bug report might be invalid.
3380b57cec5SDimitry Andric   ///
3390b57cec5SDimitry Andric   /// \sa markInvalid
3400b57cec5SDimitry Andric   /// \sa removeInvalidation
3410b57cec5SDimitry Andric   using InvalidationRecord = std::pair<const void *, const void *>;
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   /// If non-empty, this bug report is likely a false positive and should not be
3440b57cec5SDimitry Andric   /// shown to the user.
3450b57cec5SDimitry Andric   ///
3460b57cec5SDimitry Andric   /// \sa markInvalid
3470b57cec5SDimitry Andric   /// \sa removeInvalidation
3480b57cec5SDimitry Andric   llvm::SmallSet<InvalidationRecord, 4> Invalidations;
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   /// Conditions we're already tracking.
3510b57cec5SDimitry Andric   llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions;
3520b57cec5SDimitry Andric 
353a7dea167SDimitry Andric   /// Reports with different uniqueing locations are considered to be different
354a7dea167SDimitry Andric   /// for the purposes of deduplication.
355a7dea167SDimitry Andric   PathDiagnosticLocation UniqueingLocation;
356a7dea167SDimitry Andric   const Decl *UniqueingDecl;
3570b57cec5SDimitry Andric 
358a7dea167SDimitry Andric   const Stmt *getStmt() const;
359a7dea167SDimitry Andric 
360a7dea167SDimitry Andric   /// If an event occurs in a different frame than the final diagnostic,
361a7dea167SDimitry Andric   /// supply a message that will be used to construct an extra hint on the
362a7dea167SDimitry Andric   /// returns from all the calls on the stack from this event to the final
363a7dea167SDimitry Andric   /// diagnostic.
364a7dea167SDimitry Andric   // FIXME: Allow shared_ptr keys in DenseMap?
365a7dea167SDimitry Andric   std::map<PathDiagnosticPieceRef, std::unique_ptr<StackHintGenerator>>
366a7dea167SDimitry Andric       StackHints;
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric public:
PathSensitiveBugReport(const BugType & bt,StringRef desc,const ExplodedNode * errorNode)369a7dea167SDimitry Andric   PathSensitiveBugReport(const BugType &bt, StringRef desc,
370a7dea167SDimitry Andric                          const ExplodedNode *errorNode)
3715ffd83dbSDimitry Andric       : PathSensitiveBugReport(bt, desc, desc, errorNode) {}
3720b57cec5SDimitry Andric 
PathSensitiveBugReport(const BugType & bt,StringRef shortDesc,StringRef desc,const ExplodedNode * errorNode)373a7dea167SDimitry Andric   PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc,
374a7dea167SDimitry Andric                          const ExplodedNode *errorNode)
3755ffd83dbSDimitry Andric       : PathSensitiveBugReport(bt, shortDesc, desc, errorNode,
3765ffd83dbSDimitry Andric                                /*LocationToUnique*/ {},
3775ffd83dbSDimitry Andric                                /*DeclToUnique*/ nullptr) {}
3780b57cec5SDimitry Andric 
379a7dea167SDimitry Andric   /// Create a PathSensitiveBugReport with a custom uniqueing location.
3800b57cec5SDimitry Andric   ///
3810b57cec5SDimitry Andric   /// The reports that have the same report location, description, bug type, and
3820b57cec5SDimitry Andric   /// ranges are uniqued - only one of the equivalent reports will be presented
3830b57cec5SDimitry Andric   /// to the user. This method allows to rest the location which should be used
3840b57cec5SDimitry Andric   /// for uniquing reports. For example, memory leaks checker, could set this to
3850b57cec5SDimitry Andric   /// 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)386480093f4SDimitry Andric   PathSensitiveBugReport(const BugType &bt, StringRef desc,
387a7dea167SDimitry Andric                          const ExplodedNode *errorNode,
388a7dea167SDimitry Andric                          PathDiagnosticLocation LocationToUnique,
389a7dea167SDimitry Andric                          const Decl *DeclToUnique)
3905ffd83dbSDimitry Andric       : PathSensitiveBugReport(bt, desc, desc, errorNode, LocationToUnique,
3915ffd83dbSDimitry Andric                                DeclToUnique) {}
3925ffd83dbSDimitry Andric 
3935ffd83dbSDimitry Andric   PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc,
3945ffd83dbSDimitry Andric                          const ExplodedNode *errorNode,
3955ffd83dbSDimitry Andric                          PathDiagnosticLocation LocationToUnique,
3965ffd83dbSDimitry Andric                          const Decl *DeclToUnique);
3970b57cec5SDimitry Andric 
classof(const BugReport * R)398a7dea167SDimitry Andric   static bool classof(const BugReport *R) {
399a7dea167SDimitry Andric     return R->getKind() == Kind::PathSensitive;
400a7dea167SDimitry Andric   }
4010b57cec5SDimitry Andric 
getErrorNode()4020b57cec5SDimitry Andric   const ExplodedNode *getErrorNode() const { return ErrorNode; }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   /// Indicates whether or not any path pruning should take place
4050b57cec5SDimitry Andric   /// when generating a PathDiagnostic from this BugReport.
shouldPrunePath()4060b57cec5SDimitry Andric   bool shouldPrunePath() const { return !DoNotPrunePath; }
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   /// Disable all path pruning when generating a PathDiagnostic.
disablePathPruning()4090b57cec5SDimitry Andric   void disablePathPruning() { DoNotPrunePath = true; }
4100b57cec5SDimitry Andric 
411a7dea167SDimitry Andric   /// Get the location on which the report should be uniqued.
getUniqueingLocation()412a7dea167SDimitry Andric   PathDiagnosticLocation getUniqueingLocation() const override {
413a7dea167SDimitry Andric     return UniqueingLocation;
414a7dea167SDimitry Andric   }
415a7dea167SDimitry Andric 
416a7dea167SDimitry Andric   /// Get the declaration containing the uniqueing location.
getUniqueingDecl()417a7dea167SDimitry Andric   const Decl *getUniqueingDecl() const override {
418a7dea167SDimitry Andric     return UniqueingDecl;
419a7dea167SDimitry Andric   }
420a7dea167SDimitry Andric 
421a7dea167SDimitry Andric   const Decl *getDeclWithIssue() const override;
422a7dea167SDimitry Andric 
423a7dea167SDimitry Andric   ArrayRef<SourceRange> getRanges() const override;
424a7dea167SDimitry Andric 
425a7dea167SDimitry Andric   PathDiagnosticLocation getLocation() const override;
426a7dea167SDimitry Andric 
427a7dea167SDimitry Andric   /// Marks a symbol as interesting. Different kinds of interestingness will
428a7dea167SDimitry Andric   /// be processed differently by visitors (e.g. if the tracking kind is
429a7dea167SDimitry Andric   /// condition, will append "will be used as a condition" to the message).
430a7dea167SDimitry Andric   void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind =
431a7dea167SDimitry Andric                                           bugreporter::TrackingKind::Thorough);
432a7dea167SDimitry Andric 
433fe6060f1SDimitry Andric   void markNotInteresting(SymbolRef sym);
434fe6060f1SDimitry Andric 
435a7dea167SDimitry Andric   /// Marks a region as interesting. Different kinds of interestingness will
436a7dea167SDimitry Andric   /// be processed differently by visitors (e.g. if the tracking kind is
437a7dea167SDimitry Andric   /// condition, will append "will be used as a condition" to the message).
438a7dea167SDimitry Andric   void markInteresting(
439a7dea167SDimitry Andric       const MemRegion *R,
440a7dea167SDimitry Andric       bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough);
441a7dea167SDimitry Andric 
442fe6060f1SDimitry Andric   void markNotInteresting(const MemRegion *R);
443fe6060f1SDimitry Andric 
444a7dea167SDimitry Andric   /// Marks a symbolic value as interesting. Different kinds of interestingness
445a7dea167SDimitry Andric   /// will be processed differently by visitors (e.g. if the tracking kind is
446a7dea167SDimitry Andric   /// condition, will append "will be used as a condition" to the message).
447a7dea167SDimitry Andric   void markInteresting(SVal V, bugreporter::TrackingKind TKind =
448a7dea167SDimitry Andric                                    bugreporter::TrackingKind::Thorough);
4490b57cec5SDimitry Andric   void markInteresting(const LocationContext *LC);
4500b57cec5SDimitry Andric 
451a7dea167SDimitry Andric   bool isInteresting(SymbolRef sym) const;
452a7dea167SDimitry Andric   bool isInteresting(const MemRegion *R) const;
453a7dea167SDimitry Andric   bool isInteresting(SVal V) const;
454a7dea167SDimitry Andric   bool isInteresting(const LocationContext *LC) const;
455a7dea167SDimitry Andric 
456bdd1243dSDimitry Andric   std::optional<bugreporter::TrackingKind>
457a7dea167SDimitry Andric   getInterestingnessKind(SymbolRef sym) const;
458a7dea167SDimitry Andric 
459bdd1243dSDimitry Andric   std::optional<bugreporter::TrackingKind>
460a7dea167SDimitry Andric   getInterestingnessKind(const MemRegion *R) const;
461a7dea167SDimitry Andric 
462bdd1243dSDimitry Andric   std::optional<bugreporter::TrackingKind> getInterestingnessKind(SVal V) const;
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric   /// Returns whether or not this report should be considered valid.
4650b57cec5SDimitry Andric   ///
4660b57cec5SDimitry Andric   /// Invalid reports are those that have been classified as likely false
4670b57cec5SDimitry Andric   /// positives after the fact.
isValid()4680b57cec5SDimitry Andric   bool isValid() const {
4690b57cec5SDimitry Andric     return Invalidations.empty();
4700b57cec5SDimitry Andric   }
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   /// Marks the current report as invalid, meaning that it is probably a false
4730b57cec5SDimitry Andric   /// positive and should not be reported to the user.
4740b57cec5SDimitry Andric   ///
4750b57cec5SDimitry Andric   /// The \p Tag and \p Data arguments are intended to be opaque identifiers for
4760b57cec5SDimitry Andric   /// this particular invalidation, where \p Tag represents the visitor
4770b57cec5SDimitry Andric   /// responsible for invalidation, and \p Data represents the reason this
4780b57cec5SDimitry Andric   /// visitor decided to invalidate the bug report.
4790b57cec5SDimitry Andric   ///
4800b57cec5SDimitry Andric   /// \sa removeInvalidation
markInvalid(const void * Tag,const void * Data)4810b57cec5SDimitry Andric   void markInvalid(const void *Tag, const void *Data) {
4820b57cec5SDimitry Andric     Invalidations.insert(std::make_pair(Tag, Data));
4830b57cec5SDimitry Andric   }
4840b57cec5SDimitry Andric 
485a7dea167SDimitry Andric   /// Profile to identify equivalent bug reports for error report coalescing.
486a7dea167SDimitry Andric   /// Reports are uniqued to ensure that we do not emit multiple diagnostics
487a7dea167SDimitry Andric   /// for each bug.
488a7dea167SDimitry Andric   void Profile(llvm::FoldingSetNodeID &hash) const override;
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   /// Add custom or predefined bug report visitors to this report.
4910b57cec5SDimitry Andric   ///
4920b57cec5SDimitry Andric   /// The visitors should be used when the default trace is not sufficient.
4930b57cec5SDimitry Andric   /// For example, they allow constructing a more elaborate trace.
494fe6060f1SDimitry Andric   /// @{
4950b57cec5SDimitry Andric   void addVisitor(std::unique_ptr<BugReporterVisitor> visitor);
4960b57cec5SDimitry Andric 
497fe6060f1SDimitry Andric   template <class VisitorType, class... Args>
addVisitor(Args &&...ConstructorArgs)498fe6060f1SDimitry Andric   void addVisitor(Args &&... ConstructorArgs) {
499fe6060f1SDimitry Andric     addVisitor(
500fe6060f1SDimitry Andric         std::make_unique<VisitorType>(std::forward<Args>(ConstructorArgs)...));
501fe6060f1SDimitry Andric   }
502fe6060f1SDimitry Andric   /// @}
503fe6060f1SDimitry Andric 
5040b57cec5SDimitry Andric   /// Remove all visitors attached to this bug report.
5050b57cec5SDimitry Andric   void clearVisitors();
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric   /// Iterators through the custom diagnostic visitors.
visitor_begin()5080b57cec5SDimitry Andric   visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_end()5090b57cec5SDimitry Andric   visitor_iterator visitor_end() { return Callbacks.end(); }
visitors()510a7dea167SDimitry Andric   visitor_range visitors() { return {visitor_begin(), visitor_end()}; }
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric   /// Notes that the condition of the CFGBlock associated with \p Cond is
5130b57cec5SDimitry Andric   /// being tracked.
5140b57cec5SDimitry Andric   /// \returns false if the condition is already being tracked.
addTrackedCondition(const ExplodedNode * Cond)5150b57cec5SDimitry Andric   bool addTrackedCondition(const ExplodedNode *Cond) {
5160b57cec5SDimitry Andric     return TrackedConditions.insert(Cond).second;
5170b57cec5SDimitry Andric   }
5180b57cec5SDimitry Andric 
addCallStackHint(PathDiagnosticPieceRef Piece,std::unique_ptr<StackHintGenerator> StackHint)519a7dea167SDimitry Andric   void addCallStackHint(PathDiagnosticPieceRef Piece,
520a7dea167SDimitry Andric                         std::unique_ptr<StackHintGenerator> StackHint) {
521a7dea167SDimitry Andric     StackHints[Piece] = std::move(StackHint);
522a7dea167SDimitry Andric   }
523a7dea167SDimitry Andric 
hasCallStackHint(PathDiagnosticPieceRef Piece)524a7dea167SDimitry Andric   bool hasCallStackHint(PathDiagnosticPieceRef Piece) const {
525a7dea167SDimitry Andric     return StackHints.count(Piece) > 0;
526a7dea167SDimitry Andric   }
527a7dea167SDimitry Andric 
528a7dea167SDimitry Andric   /// Produce the hint for the given node. The node contains
529a7dea167SDimitry Andric   /// information about the call for which the diagnostic can be generated.
530a7dea167SDimitry Andric   std::string
getCallStackMessage(PathDiagnosticPieceRef Piece,const ExplodedNode * N)531a7dea167SDimitry Andric   getCallStackMessage(PathDiagnosticPieceRef Piece,
532a7dea167SDimitry Andric                       const ExplodedNode *N) const {
533a7dea167SDimitry Andric     auto I = StackHints.find(Piece);
534a7dea167SDimitry Andric     if (I != StackHints.end())
535a7dea167SDimitry Andric       return I->second->getMessage(N);
536a7dea167SDimitry Andric     return "";
537a7dea167SDimitry Andric   }
5380b57cec5SDimitry Andric };
5390b57cec5SDimitry Andric 
5400b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5410b57cec5SDimitry Andric // BugTypes (collections of related reports).
5420b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric class BugReportEquivClass : public llvm::FoldingSetNode {
5450b57cec5SDimitry Andric   friend class BugReporter;
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric   /// List of *owned* BugReport objects.
548a7dea167SDimitry Andric   llvm::SmallVector<std::unique_ptr<BugReport>, 4> Reports;
5490b57cec5SDimitry Andric 
AddReport(std::unique_ptr<BugReport> && R)550a7dea167SDimitry Andric   void AddReport(std::unique_ptr<BugReport> &&R) {
551a7dea167SDimitry Andric     Reports.push_back(std::move(R));
5520b57cec5SDimitry Andric   }
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric public:
BugReportEquivClass(std::unique_ptr<BugReport> R)5550b57cec5SDimitry Andric   BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); }
556a7dea167SDimitry Andric 
getReports()557a7dea167SDimitry Andric   ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; }
5580b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID)5590b57cec5SDimitry Andric   void Profile(llvm::FoldingSetNodeID& ID) const {
5600b57cec5SDimitry Andric     assert(!Reports.empty());
561a7dea167SDimitry Andric     Reports.front()->Profile(ID);
5620b57cec5SDimitry Andric   }
5630b57cec5SDimitry Andric };
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5660b57cec5SDimitry Andric // BugReporter and friends.
5670b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric class BugReporterData {
5700b57cec5SDimitry Andric public:
571a7dea167SDimitry Andric   virtual ~BugReporterData() = default;
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0;
5740b57cec5SDimitry Andric   virtual ASTContext &getASTContext() = 0;
5750b57cec5SDimitry Andric   virtual SourceManager &getSourceManager() = 0;
5760b57cec5SDimitry Andric   virtual AnalyzerOptions &getAnalyzerOptions() = 0;
5775ffd83dbSDimitry Andric   virtual Preprocessor &getPreprocessor() = 0;
5780b57cec5SDimitry Andric };
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric /// BugReporter is a utility class for generating PathDiagnostics for analysis.
5810b57cec5SDimitry Andric /// It collects the BugReports and BugTypes and knows how to generate
5820b57cec5SDimitry Andric /// and flush the corresponding diagnostics.
5830b57cec5SDimitry Andric ///
5840b57cec5SDimitry Andric /// The base class is used for generating path-insensitive
5850b57cec5SDimitry Andric class BugReporter {
5860b57cec5SDimitry Andric private:
5870b57cec5SDimitry Andric   BugReporterData& D;
5880b57cec5SDimitry Andric 
5890b57cec5SDimitry Andric   /// Generate and flush the diagnostics for the given bug report.
5900b57cec5SDimitry Andric   void FlushReport(BugReportEquivClass& EQ);
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   /// The set of bug reports tracked by the BugReporter.
5930b57cec5SDimitry Andric   llvm::FoldingSet<BugReportEquivClass> EQClasses;
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric   /// A vector of BugReports for tracking the allocated pointers and cleanup.
5960b57cec5SDimitry Andric   std::vector<BugReportEquivClass *> EQClassesVector;
5970b57cec5SDimitry Andric 
5985f757f3fSDimitry Andric   /// User-provided in-code suppressions.
5995f757f3fSDimitry Andric   BugSuppression UserSuppressions;
6005f757f3fSDimitry Andric 
6010b57cec5SDimitry Andric public:
6025ffd83dbSDimitry Andric   BugReporter(BugReporterData &d);
6030b57cec5SDimitry Andric   virtual ~BugReporter();
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric   /// Generate and flush diagnostics for all bug reports.
6060b57cec5SDimitry Andric   void FlushReports();
6070b57cec5SDimitry Andric 
getPathDiagnosticConsumers()6080b57cec5SDimitry Andric   ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() {
6090b57cec5SDimitry Andric     return D.getPathDiagnosticConsumers();
6100b57cec5SDimitry Andric   }
6110b57cec5SDimitry Andric 
6120b57cec5SDimitry Andric   /// Iterator over the set of BugReports tracked by the BugReporter.
6130b57cec5SDimitry Andric   using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator;
equivalenceClasses()61406c3fb27SDimitry Andric   llvm::iterator_range<EQClasses_iterator> equivalenceClasses() {
61506c3fb27SDimitry Andric     return EQClasses;
61606c3fb27SDimitry Andric   }
6170b57cec5SDimitry Andric 
getContext()6180b57cec5SDimitry Andric   ASTContext &getContext() { return D.getASTContext(); }
6190b57cec5SDimitry Andric 
getSourceManager()620a7dea167SDimitry Andric   const SourceManager &getSourceManager() { return D.getSourceManager(); }
6210b57cec5SDimitry Andric 
getAnalyzerOptions()622a7dea167SDimitry Andric   const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
6230b57cec5SDimitry Andric 
getPreprocessor()6245ffd83dbSDimitry Andric   Preprocessor &getPreprocessor() { return D.getPreprocessor(); }
6255ffd83dbSDimitry Andric 
6260b57cec5SDimitry Andric   /// Add the given report to the set of reports tracked by BugReporter.
6270b57cec5SDimitry Andric   ///
6280b57cec5SDimitry Andric   /// The reports are usually generated by the checkers. Further, they are
6290b57cec5SDimitry Andric   /// folded based on the profile value, which is done to coalesce similar
6300b57cec5SDimitry Andric   /// reports.
631a7dea167SDimitry Andric   virtual void emitReport(std::unique_ptr<BugReport> R);
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric   void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker,
6340b57cec5SDimitry Andric                        StringRef BugName, StringRef BugCategory,
6350b57cec5SDimitry Andric                        StringRef BugStr, PathDiagnosticLocation Loc,
636bdd1243dSDimitry Andric                        ArrayRef<SourceRange> Ranges = std::nullopt,
637bdd1243dSDimitry Andric                        ArrayRef<FixItHint> Fixits = std::nullopt);
6380b57cec5SDimitry Andric 
639a7dea167SDimitry Andric   void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName,
6400b57cec5SDimitry Andric                        StringRef BugName, StringRef BugCategory,
6410b57cec5SDimitry Andric                        StringRef BugStr, PathDiagnosticLocation Loc,
642bdd1243dSDimitry Andric                        ArrayRef<SourceRange> Ranges = std::nullopt,
643bdd1243dSDimitry Andric                        ArrayRef<FixItHint> Fixits = std::nullopt);
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric private:
6465ffd83dbSDimitry Andric   llvm::StringMap<std::unique_ptr<BugType>> StrBugTypes;
6470b57cec5SDimitry Andric 
6480b57cec5SDimitry Andric   /// Returns a BugType that is associated with the given name and
6490b57cec5SDimitry Andric   /// category.
650a7dea167SDimitry Andric   BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name,
6510b57cec5SDimitry Andric                              StringRef category);
652a7dea167SDimitry Andric 
653a7dea167SDimitry Andric   virtual BugReport *
findReportInEquivalenceClass(BugReportEquivClass & eqClass,SmallVectorImpl<BugReport * > & bugReports)654a7dea167SDimitry Andric   findReportInEquivalenceClass(BugReportEquivClass &eqClass,
655a7dea167SDimitry Andric                                SmallVectorImpl<BugReport *> &bugReports) {
656a7dea167SDimitry Andric     return eqClass.getReports()[0].get();
657a7dea167SDimitry Andric   }
658a7dea167SDimitry Andric 
659a7dea167SDimitry Andric protected:
660a7dea167SDimitry Andric   /// Generate the diagnostics for the given bug report.
661a7dea167SDimitry Andric   virtual std::unique_ptr<DiagnosticForConsumerMapTy>
662a7dea167SDimitry Andric   generateDiagnosticForConsumerMap(BugReport *exampleReport,
663a7dea167SDimitry Andric                                    ArrayRef<PathDiagnosticConsumer *> consumers,
664a7dea167SDimitry Andric                                    ArrayRef<BugReport *> bugReports);
6650b57cec5SDimitry Andric };
6660b57cec5SDimitry Andric 
6670b57cec5SDimitry Andric /// GRBugReporter is used for generating path-sensitive reports.
668a7dea167SDimitry Andric class PathSensitiveBugReporter final : public BugReporter {
6690b57cec5SDimitry Andric   ExprEngine& Eng;
6700b57cec5SDimitry Andric 
671a7dea167SDimitry Andric   BugReport *findReportInEquivalenceClass(
672a7dea167SDimitry Andric       BugReportEquivClass &eqClass,
673a7dea167SDimitry Andric       SmallVectorImpl<BugReport *> &bugReports) override;
6740b57cec5SDimitry Andric 
675a7dea167SDimitry Andric   /// Generate the diagnostics for the given bug report.
676a7dea167SDimitry Andric   std::unique_ptr<DiagnosticForConsumerMapTy>
677a7dea167SDimitry Andric   generateDiagnosticForConsumerMap(BugReport *exampleReport,
678a7dea167SDimitry Andric                                    ArrayRef<PathDiagnosticConsumer *> consumers,
679a7dea167SDimitry Andric                                    ArrayRef<BugReport *> bugReports) override;
680a7dea167SDimitry Andric public:
PathSensitiveBugReporter(BugReporterData & d,ExprEngine & eng)681a7dea167SDimitry Andric   PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng)
682a7dea167SDimitry Andric       : BugReporter(d), Eng(eng) {}
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric   /// getGraph - Get the exploded graph created by the analysis engine
6850b57cec5SDimitry Andric   ///  for the analyzed method or function.
686a7dea167SDimitry Andric   const ExplodedGraph &getGraph() const;
6870b57cec5SDimitry Andric 
6880b57cec5SDimitry Andric   /// getStateManager - Return the state manager used by the analysis
6890b57cec5SDimitry Andric   ///  engine.
690a7dea167SDimitry Andric   ProgramStateManager &getStateManager() const;
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   /// \p bugReports A set of bug reports within a *single* equivalence class
6930b57cec5SDimitry Andric   ///
6940b57cec5SDimitry Andric   /// \return A mapping from consumers to the corresponding diagnostics.
6950b57cec5SDimitry Andric   /// Iterates through the bug reports within a single equivalence class,
6960b57cec5SDimitry Andric   /// stops at a first non-invalidated report.
697a7dea167SDimitry Andric   std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics(
698a7dea167SDimitry Andric       ArrayRef<PathDiagnosticConsumer *> consumers,
699a7dea167SDimitry Andric       ArrayRef<PathSensitiveBugReport *> &bugReports);
7000b57cec5SDimitry Andric 
701a7dea167SDimitry Andric   void emitReport(std::unique_ptr<BugReport> R) override;
7020b57cec5SDimitry Andric };
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric 
7050b57cec5SDimitry Andric class BugReporterContext {
706a7dea167SDimitry Andric   PathSensitiveBugReporter &BR;
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric   virtual void anchor();
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric public:
BugReporterContext(PathSensitiveBugReporter & br)711a7dea167SDimitry Andric   BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {}
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric   virtual ~BugReporterContext() = default;
7140b57cec5SDimitry Andric 
getBugReporter()715a7dea167SDimitry Andric   PathSensitiveBugReporter& getBugReporter() { return BR; }
7160b57cec5SDimitry Andric 
getStateManager()717a7dea167SDimitry Andric   ProgramStateManager& getStateManager() const {
7180b57cec5SDimitry Andric     return BR.getStateManager();
7190b57cec5SDimitry Andric   }
7200b57cec5SDimitry Andric 
getASTContext()721a7dea167SDimitry Andric   ASTContext &getASTContext() const {
7220b57cec5SDimitry Andric     return BR.getContext();
7230b57cec5SDimitry Andric   }
7240b57cec5SDimitry Andric 
getSourceManager()725a7dea167SDimitry Andric   const SourceManager& getSourceManager() const {
7260b57cec5SDimitry Andric     return BR.getSourceManager();
7270b57cec5SDimitry Andric   }
7280b57cec5SDimitry Andric 
getAnalyzerOptions()729a7dea167SDimitry Andric   const AnalyzerOptions &getAnalyzerOptions() const {
7300b57cec5SDimitry Andric     return BR.getAnalyzerOptions();
7310b57cec5SDimitry Andric   }
7320b57cec5SDimitry Andric };
7330b57cec5SDimitry Andric 
734fe6060f1SDimitry Andric /// The tag that carries some information with it.
735fe6060f1SDimitry Andric ///
736fe6060f1SDimitry Andric /// It can be valuable to produce tags with some bits of information and later
737fe6060f1SDimitry Andric /// reuse them for a better diagnostic.
738fe6060f1SDimitry Andric ///
739fe6060f1SDimitry Andric /// Please make sure that derived class' constuctor is private and that the user
740fe6060f1SDimitry Andric /// can only create objects using DataTag::Factory.  This also means that
741fe6060f1SDimitry Andric /// DataTag::Factory should be friend for every derived class.
742fe6060f1SDimitry Andric class DataTag : public ProgramPointTag {
743fe6060f1SDimitry Andric public:
getTagDescription()744fe6060f1SDimitry Andric   StringRef getTagDescription() const override { return "Data Tag"; }
745fe6060f1SDimitry Andric 
746fe6060f1SDimitry Andric   // Manage memory for DataTag objects.
747fe6060f1SDimitry Andric   class Factory {
748fe6060f1SDimitry Andric     std::vector<std::unique_ptr<DataTag>> Tags;
749fe6060f1SDimitry Andric 
750fe6060f1SDimitry Andric   public:
751fe6060f1SDimitry Andric     template <class DataTagType, class... Args>
make(Args &&...ConstructorArgs)752fe6060f1SDimitry Andric     const DataTagType *make(Args &&... ConstructorArgs) {
753fe6060f1SDimitry Andric       // We cannot use std::make_unique because we cannot access the private
754fe6060f1SDimitry Andric       // constructor from inside it.
755fe6060f1SDimitry Andric       Tags.emplace_back(
756fe6060f1SDimitry Andric           new DataTagType(std::forward<Args>(ConstructorArgs)...));
757fe6060f1SDimitry Andric       return static_cast<DataTagType *>(Tags.back().get());
758fe6060f1SDimitry Andric     }
759fe6060f1SDimitry Andric   };
760fe6060f1SDimitry Andric 
761fe6060f1SDimitry Andric protected:
DataTag(void * TagKind)762fe6060f1SDimitry Andric   DataTag(void *TagKind) : ProgramPointTag(TagKind) {}
763fe6060f1SDimitry Andric };
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric /// The tag upon which the TagVisitor reacts. Add these in order to display
7660b57cec5SDimitry Andric /// additional PathDiagnosticEventPieces along the path.
767fe6060f1SDimitry Andric class NoteTag : public DataTag {
7680b57cec5SDimitry Andric public:
769fe6060f1SDimitry Andric   using Callback = std::function<std::string(BugReporterContext &,
7705ffd83dbSDimitry Andric                                              PathSensitiveBugReport &)>;
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric private:
7730b57cec5SDimitry Andric   static int Kind;
7740b57cec5SDimitry Andric 
7750b57cec5SDimitry Andric   const Callback Cb;
7760b57cec5SDimitry Andric   const bool IsPrunable;
7770b57cec5SDimitry Andric 
NoteTag(Callback && Cb,bool IsPrunable)7780b57cec5SDimitry Andric   NoteTag(Callback &&Cb, bool IsPrunable)
779fe6060f1SDimitry Andric       : DataTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {}
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric public:
classof(const ProgramPointTag * T)7820b57cec5SDimitry Andric   static bool classof(const ProgramPointTag *T) {
7830b57cec5SDimitry Andric     return T->getTagKind() == &Kind;
7840b57cec5SDimitry Andric   }
7850b57cec5SDimitry Andric 
generateMessage(BugReporterContext & BRC,PathSensitiveBugReport & R)786bdd1243dSDimitry Andric   std::optional<std::string> generateMessage(BugReporterContext &BRC,
7875ffd83dbSDimitry Andric                                              PathSensitiveBugReport &R) const {
7880b57cec5SDimitry Andric     std::string Msg = Cb(BRC, R);
7890b57cec5SDimitry Andric     if (Msg.empty())
790bdd1243dSDimitry Andric       return std::nullopt;
7910b57cec5SDimitry Andric 
7920b57cec5SDimitry Andric     return std::move(Msg);
7930b57cec5SDimitry Andric   }
7940b57cec5SDimitry Andric 
getTagDescription()7950b57cec5SDimitry Andric   StringRef getTagDescription() const override {
7960b57cec5SDimitry Andric     // TODO: Remember a few examples of generated messages
7970b57cec5SDimitry Andric     // and display them in the ExplodedGraph dump by
7980b57cec5SDimitry Andric     // returning them from this function.
7990b57cec5SDimitry Andric     return "Note Tag";
8000b57cec5SDimitry Andric   }
8010b57cec5SDimitry Andric 
isPrunable()8020b57cec5SDimitry Andric   bool isPrunable() const { return IsPrunable; }
8030b57cec5SDimitry Andric 
804fe6060f1SDimitry Andric   friend class Factory;
8050b57cec5SDimitry Andric   friend class TagVisitor;
8060b57cec5SDimitry Andric };
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric } // namespace ento
8090b57cec5SDimitry Andric 
8100b57cec5SDimitry Andric } // namespace clang
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
813