aboutsummaryrefslogtreecommitdiffstats
path: root/include/clang/StaticAnalyzer/Core/BugReporter
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-10-23 17:52:09 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-10-23 17:52:09 +0000
commit519fc96c475680de2cc49e7811dbbfadb912cbcc (patch)
tree310ca684459b7e9ae13c9a3b9abf308b3a634afe /include/clang/StaticAnalyzer/Core/BugReporter
parent2298981669bf3bd63335a4be179bc0f96823a8f4 (diff)
downloadsrc-vendor/clang.tar.gz
src-vendor/clang.zip
Vendor import of stripped clang trunk r375505, the last commit beforevendor/clang/clang-trunk-r375505vendor/clang
the upstream Subversion repository was made read-only, and the LLVM project migrated to GitHub: https://llvm.org/svn/llvm-project/cfe/trunk@375505
Notes
Notes: svn path=/vendor/clang/dist/; revision=353942 svn path=/vendor/clang/clang-r375505/; revision=353943; tag=vendor/clang/clang-trunk-r375505
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/BugReporter')
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h656
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h217
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h923
5 files changed, 531 insertions, 1306 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index d30ad19b20f8..e94b544172a0 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@@ -70,59 +70,253 @@ class SValBuilder;
using DiagnosticForConsumerMapTy =
llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>;
-/// This class provides an interface through which checkers can create
-/// individual bug reports.
-class BugReport : public llvm::ilist_node<BugReport> {
+/// Interface for classes constructing Stack hints.
+///
+/// If a PathDiagnosticEvent occurs in a different frame than the final
+/// diagnostic the hints can be used to summarize the effect of the call.
+class StackHintGenerator {
public:
- class NodeResolver {
- virtual void anchor();
+ virtual ~StackHintGenerator() = 0;
- public:
- virtual ~NodeResolver() = default;
+ /// Construct the Diagnostic message for the given ExplodedNode.
+ virtual std::string getMessage(const ExplodedNode *N) = 0;
+};
- virtual const ExplodedNode*
- getOriginalNode(const ExplodedNode *N) = 0;
- };
+/// Constructs a Stack hint for the given symbol.
+///
+/// The class knows how to construct the stack hint message based on
+/// traversing the CallExpr associated with the call and checking if the given
+/// symbol is returned or is one of the arguments.
+/// The hint can be customized by redefining 'getMessageForX()' methods.
+class StackHintGeneratorForSymbol : public StackHintGenerator {
+private:
+ SymbolRef Sym;
+ std::string Msg;
- using ranges_iterator = const SourceRange *;
- using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>;
- using visitor_iterator = VisitorList::iterator;
- using ExtraTextList = SmallVector<StringRef, 2>;
- using NoteList = SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4>;
+public:
+ StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
+ ~StackHintGeneratorForSymbol() override = default;
+
+ /// Search the call expression for the symbol Sym and dispatch the
+ /// 'getMessageForX()' methods to construct a specific message.
+ std::string getMessage(const ExplodedNode *N) override;
+
+ /// Produces the message of the following form:
+ /// 'Msg via Nth parameter'
+ virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
+
+ virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
+ return Msg;
+ }
+
+ virtual std::string getMessageForSymbolNotFound() {
+ return Msg;
+ }
+};
+
+/// This class provides an interface through which checkers can create
+/// individual bug reports.
+class BugReport {
+public:
+ enum class Kind { Basic, PathSensitive };
protected:
friend class BugReportEquivClass;
friend class BugReporter;
+ Kind K;
const BugType& BT;
- const Decl *DeclWithIssue = nullptr;
std::string ShortDescription;
std::string Description;
+
+ SmallVector<SourceRange, 4> Ranges;
+ SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> Notes;
+ SmallVector<FixItHint, 4> Fixits;
+
+ BugReport(Kind kind, const BugType &bt, StringRef desc)
+ : K(kind), BT(bt), Description(desc) {}
+
+ BugReport(Kind K, const BugType &BT, StringRef ShortDescription,
+ StringRef Description)
+ : K(K), BT(BT), ShortDescription(ShortDescription),
+ Description(Description) {}
+
+public:
+ virtual ~BugReport() = default;
+
+ Kind getKind() const { return K; }
+
+ const BugType& getBugType() const { return BT; }
+
+ /// A verbose warning message that is appropriate for displaying next to
+ /// the source code that introduces the problem. The description should be
+ /// at least a full sentence starting with a capital letter. The period at
+ /// the end of the warning is traditionally omitted. If the description
+ /// consists of multiple sentences, periods between the sentences are
+ /// encouraged, but the period at the end of the description is still omitted.
+ StringRef getDescription() const { return Description; }
+
+ /// A short general warning message that is appropriate for displaying in
+ /// the list of all reported bugs. It should describe what kind of bug is found
+ /// but does not need to try to go into details of that specific bug.
+ /// Grammatical conventions of getDescription() apply here as well.
+ StringRef getShortDescription(bool UseFallback = true) const {
+ if (ShortDescription.empty() && UseFallback)
+ return Description;
+ return ShortDescription;
+ }
+
+ /// The primary location of the bug report that points at the undesirable
+ /// behavior in the code. UIs should attach the warning description to this
+ /// location. The warning description should describe the bad behavior
+ /// at this location.
+ virtual PathDiagnosticLocation getLocation() const = 0;
+
+ /// The smallest declaration that contains the bug location.
+ /// This is purely cosmetic; the declaration can be displayed to the user
+ /// but it does not affect whether the report is emitted.
+ virtual const Decl *getDeclWithIssue() const = 0;
+
+ /// Get the location on which the report should be uniqued. Two warnings are
+ /// considered to be equivalent whenever they have the same bug types,
+ /// descriptions, and uniqueing locations. Out of a class of equivalent
+ /// warnings only one gets displayed to the user. For most warnings the
+ /// uniqueing location coincides with their location, but sometimes
+ /// it makes sense to use different locations. For example, a leak
+ /// checker can place the warning at the location where the last reference
+ /// to the leaking resource is dropped but at the same time unique the warning
+ /// by where that resource is acquired (allocated).
+ virtual PathDiagnosticLocation getUniqueingLocation() const = 0;
+
+ /// Get the declaration that corresponds to (usually contains) the uniqueing
+ /// location. This is not actively used for uniqueing, i.e. otherwise
+ /// identical reports that have different uniqueing decls will be considered
+ /// equivalent.
+ virtual const Decl *getUniqueingDecl() const = 0;
+
+ /// Add new item to the list of additional notes that need to be attached to
+ /// this report. If the report is path-sensitive, these notes will not be
+ /// displayed as part of the execution path explanation, but will be displayed
+ /// separately. Use bug visitors if you need to add an extra path note.
+ void addNote(StringRef Msg, const PathDiagnosticLocation &Pos,
+ ArrayRef<SourceRange> Ranges = {}) {
+ auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg);
+
+ for (const auto &R : Ranges)
+ P->addRange(R);
+
+ Notes.push_back(std::move(P));
+ }
+
+ ArrayRef<std::shared_ptr<PathDiagnosticNotePiece>> getNotes() {
+ return Notes;
+ }
+
+ /// Add a range to a bug report.
+ ///
+ /// Ranges are used to highlight regions of interest in the source code.
+ /// They should be at the same source code line as the BugReport location.
+ /// By default, the source range of the statement corresponding to the error
+ /// node will be used; add a single invalid range to specify absence of
+ /// ranges.
+ void addRange(SourceRange R) {
+ assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
+ "to specify that the report does not have a range.");
+ Ranges.push_back(R);
+ }
+
+ /// Get the SourceRanges associated with the report.
+ virtual ArrayRef<SourceRange> getRanges() const {
+ return Ranges;
+ }
+
+ /// Add a fix-it hint to the bug report.
+ ///
+ /// Fix-it hints are the suggested edits to the code that would resolve
+ /// the problem explained by the bug report. Fix-it hints should be
+ /// as conservative as possible because it is not uncommon for the user
+ /// to blindly apply all fixits to their project. Note that it is very hard
+ /// to produce a good fix-it hint for most path-sensitive warnings.
+ void addFixItHint(const FixItHint &F) {
+ Fixits.push_back(F);
+ }
+
+ llvm::ArrayRef<FixItHint> getFixits() const { return Fixits; }
+
+ /// Reports are uniqued to ensure that we do not emit multiple diagnostics
+ /// for each bug.
+ virtual void Profile(llvm::FoldingSetNodeID& hash) const = 0;
+};
+
+class BasicBugReport : public BugReport {
PathDiagnosticLocation Location;
- PathDiagnosticLocation UniqueingLocation;
- const Decl *UniqueingDecl;
+ const Decl *DeclWithIssue = nullptr;
+
+public:
+ BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l)
+ : BugReport(Kind::Basic, bt, desc), Location(l) {}
+
+ static bool classof(const BugReport *R) {
+ return R->getKind() == Kind::Basic;
+ }
+
+ PathDiagnosticLocation getLocation() const override {
+ assert(Location.isValid());
+ return Location;
+ }
+
+ const Decl *getDeclWithIssue() const override {
+ return DeclWithIssue;
+ }
+
+ PathDiagnosticLocation getUniqueingLocation() const override {
+ return getLocation();
+ }
+
+ const Decl *getUniqueingDecl() const override {
+ return getDeclWithIssue();
+ }
+
+ /// Specifically set the Decl where an issue occurred. This isn't necessary
+ /// for BugReports that cover a path as it will be automatically inferred.
+ void setDeclWithIssue(const Decl *declWithIssue) {
+ DeclWithIssue = declWithIssue;
+ }
+ void Profile(llvm::FoldingSetNodeID& hash) const override;
+};
+
+class PathSensitiveBugReport : public BugReport {
+public:
+ using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>;
+ using visitor_iterator = VisitorList::iterator;
+ using visitor_range = llvm::iterator_range<visitor_iterator>;
+
+protected:
+ /// The ExplodedGraph node against which the report was thrown. It corresponds
+ /// to the end of the execution path that demonstrates the bug.
const ExplodedNode *ErrorNode = nullptr;
- SmallVector<SourceRange, 4> Ranges;
- ExtraTextList ExtraText;
- NoteList Notes;
- using Symbols = llvm::DenseSet<SymbolRef>;
- using Regions = llvm::DenseSet<const MemRegion *>;
+ /// The range that corresponds to ErrorNode's program point. It is usually
+ /// highlighted in the report.
+ const SourceRange ErrorNodeRange;
+
+ /// Profile to identify equivalent bug reports for error report coalescing.
/// A (stack of) a set of symbols that are registered with this
/// report as being "interesting", and thus used to help decide which
/// diagnostics to include when constructing the final path diagnostic.
/// The stack is largely used by BugReporter when generating PathDiagnostics
/// for multiple PathDiagnosticConsumers.
- SmallVector<Symbols *, 2> interestingSymbols;
+ llvm::DenseMap<SymbolRef, bugreporter::TrackingKind> InterestingSymbols;
/// A (stack of) set of regions that are registered with this report as being
/// "interesting", and thus used to help decide which diagnostics
/// to include when constructing the final path diagnostic.
/// The stack is largely used by BugReporter when generating PathDiagnostics
/// for multiple PathDiagnosticConsumers.
- SmallVector<Regions *, 2> interestingRegions;
+ llvm::DenseMap<const MemRegion *, bugreporter::TrackingKind>
+ InterestingRegions;
/// A set of location contexts that correspoind to call sites which should be
/// considered "interesting".
@@ -156,66 +350,58 @@ protected:
/// Conditions we're already tracking.
llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions;
-private:
- // Used internally by BugReporter.
- Symbols &getInterestingSymbols();
- Regions &getInterestingRegions();
-
- void lazyInitializeInterestingSets();
- void pushInterestingSymbolsAndRegions();
- void popInterestingSymbolsAndRegions();
-
-public:
- BugReport(const BugType& bt, StringRef desc, const ExplodedNode *errornode)
- : BT(bt), Description(desc), ErrorNode(errornode) {}
+ /// Reports with different uniqueing locations are considered to be different
+ /// for the purposes of deduplication.
+ PathDiagnosticLocation UniqueingLocation;
+ const Decl *UniqueingDecl;
- BugReport(const BugType& bt, StringRef shortDesc, StringRef desc,
- const ExplodedNode *errornode)
- : BT(bt), ShortDescription(shortDesc), Description(desc),
- ErrorNode(errornode) {}
+ const Stmt *getStmt() const;
- BugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l)
- : BT(bt), Description(desc), Location(l) {}
+ /// If an event occurs in a different frame than the final diagnostic,
+ /// supply a message that will be used to construct an extra hint on the
+ /// returns from all the calls on the stack from this event to the final
+ /// diagnostic.
+ // FIXME: Allow shared_ptr keys in DenseMap?
+ std::map<PathDiagnosticPieceRef, std::unique_ptr<StackHintGenerator>>
+ StackHints;
- /// Create a BugReport with a custom uniqueing location.
+public:
+ PathSensitiveBugReport(const BugType &bt, StringRef desc,
+ const ExplodedNode *errorNode)
+ : BugReport(Kind::PathSensitive, bt, desc), ErrorNode(errorNode),
+ ErrorNodeRange(getStmt() ? getStmt()->getSourceRange()
+ : SourceRange()) {}
+
+ PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc,
+ const ExplodedNode *errorNode)
+ : BugReport(Kind::PathSensitive, bt, shortDesc, desc),
+ ErrorNode(errorNode),
+ ErrorNodeRange(getStmt() ? getStmt()->getSourceRange()
+ : SourceRange()) {}
+
+ /// Create a PathSensitiveBugReport with a custom uniqueing location.
///
/// The reports that have the same report location, description, bug type, and
/// ranges are uniqued - only one of the equivalent reports will be presented
/// to the user. This method allows to rest the location which should be used
/// for uniquing reports. For example, memory leaks checker, could set this to
/// the allocation site, rather then the location where the bug is reported.
- BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode,
- PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique)
- : BT(bt), Description(desc), UniqueingLocation(LocationToUnique),
- UniqueingDecl(DeclToUnique), ErrorNode(errornode) {}
-
- virtual ~BugReport();
-
- const BugType& getBugType() const { return BT; }
- //BugType& getBugType() { return BT; }
+ PathSensitiveBugReport(BugType &bt, StringRef desc,
+ const ExplodedNode *errorNode,
+ PathDiagnosticLocation LocationToUnique,
+ const Decl *DeclToUnique)
+ : BugReport(Kind::PathSensitive, bt, desc), ErrorNode(errorNode),
+ ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() : SourceRange()),
+ UniqueingLocation(LocationToUnique), UniqueingDecl(DeclToUnique) {
+ assert(errorNode);
+ }
- /// True when the report has an execution path associated with it.
- ///
- /// A report is said to be path-sensitive if it was thrown against a
- /// particular exploded node in the path-sensitive analysis graph.
- /// Path-sensitive reports have their intermediate path diagnostics
- /// auto-generated, perhaps with the help of checker-defined visitors,
- /// and may contain extra notes.
- /// Path-insensitive reports consist only of a single warning message
- /// in a specific location, and perhaps extra notes.
- /// Path-sensitive checkers are allowed to throw path-insensitive reports.
- bool isPathSensitive() const { return ErrorNode != nullptr; }
+ static bool classof(const BugReport *R) {
+ return R->getKind() == Kind::PathSensitive;
+ }
const ExplodedNode *getErrorNode() const { return ErrorNode; }
- StringRef getDescription() const { return Description; }
-
- StringRef getShortDescription(bool UseFallback = true) const {
- if (ShortDescription.empty() && UseFallback)
- return Description;
- return ShortDescription;
- }
-
/// Indicates whether or not any path pruning should take place
/// when generating a PathDiagnostic from this BugReport.
bool shouldPrunePath() const { return !DoNotPrunePath; }
@@ -223,15 +409,54 @@ public:
/// Disable all path pruning when generating a PathDiagnostic.
void disablePathPruning() { DoNotPrunePath = true; }
- void markInteresting(SymbolRef sym);
- void markInteresting(const MemRegion *R);
- void markInteresting(SVal V);
+ /// Get the location on which the report should be uniqued.
+ PathDiagnosticLocation getUniqueingLocation() const override {
+ return UniqueingLocation;
+ }
+
+ /// Get the declaration containing the uniqueing location.
+ const Decl *getUniqueingDecl() const override {
+ return UniqueingDecl;
+ }
+
+ const Decl *getDeclWithIssue() const override;
+
+ ArrayRef<SourceRange> getRanges() const override;
+
+ PathDiagnosticLocation getLocation() const override;
+
+ /// Marks a symbol as interesting. Different kinds of interestingness will
+ /// be processed differently by visitors (e.g. if the tracking kind is
+ /// condition, will append "will be used as a condition" to the message).
+ void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind =
+ bugreporter::TrackingKind::Thorough);
+
+ /// Marks a region as interesting. Different kinds of interestingness will
+ /// be processed differently by visitors (e.g. if the tracking kind is
+ /// condition, will append "will be used as a condition" to the message).
+ void markInteresting(
+ const MemRegion *R,
+ bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough);
+
+ /// Marks a symbolic value as interesting. Different kinds of interestingness
+ /// will be processed differently by visitors (e.g. if the tracking kind is
+ /// condition, will append "will be used as a condition" to the message).
+ void markInteresting(SVal V, bugreporter::TrackingKind TKind =
+ bugreporter::TrackingKind::Thorough);
void markInteresting(const LocationContext *LC);
- bool isInteresting(SymbolRef sym);
- bool isInteresting(const MemRegion *R);
- bool isInteresting(SVal V);
- bool isInteresting(const LocationContext *LC);
+ bool isInteresting(SymbolRef sym) const;
+ bool isInteresting(const MemRegion *R) const;
+ bool isInteresting(SVal V) const;
+ bool isInteresting(const LocationContext *LC) const;
+
+ Optional<bugreporter::TrackingKind>
+ getInterestingnessKind(SymbolRef sym) const;
+
+ Optional<bugreporter::TrackingKind>
+ getInterestingnessKind(const MemRegion *R) const;
+
+ Optional<bugreporter::TrackingKind> getInterestingnessKind(SVal V) const;
/// Returns whether or not this report should be considered valid.
///
@@ -254,87 +479,10 @@ public:
Invalidations.insert(std::make_pair(Tag, Data));
}
- /// Return the canonical declaration, be it a method or class, where
- /// this issue semantically occurred.
- const Decl *getDeclWithIssue() const;
-
- /// Specifically set the Decl where an issue occurred. This isn't necessary
- /// for BugReports that cover a path as it will be automatically inferred.
- void setDeclWithIssue(const Decl *declWithIssue) {
- DeclWithIssue = declWithIssue;
- }
-
- /// Add new item to the list of additional notes that need to be attached to
- /// this path-insensitive report. If you want to add extra notes to a
- /// path-sensitive report, you need to use a BugReporterVisitor because it
- /// allows you to specify where exactly in the auto-generated path diagnostic
- /// the extra note should appear.
- void addNote(StringRef Msg, const PathDiagnosticLocation &Pos,
- ArrayRef<SourceRange> Ranges) {
- auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg);
-
- for (const auto &R : Ranges)
- P->addRange(R);
-
- Notes.push_back(std::move(P));
- }
-
- // FIXME: Instead of making an override, we could have default-initialized
- // Ranges with {}, however it crashes the MSVC 2013 compiler.
- void addNote(StringRef Msg, const PathDiagnosticLocation &Pos) {
- std::vector<SourceRange> Ranges;
- addNote(Msg, Pos, Ranges);
- }
-
- virtual const NoteList &getNotes() {
- return Notes;
- }
-
- /// This allows for addition of meta data to the diagnostic.
- ///
- /// Currently, only the HTMLDiagnosticClient knows how to display it.
- void addExtraText(StringRef S) {
- ExtraText.push_back(S);
- }
-
- virtual const ExtraTextList &getExtraText() {
- return ExtraText;
- }
-
- /// Return the "definitive" location of the reported bug.
- ///
- /// While a bug can span an entire path, usually there is a specific
- /// location that can be used to identify where the key issue occurred.
- /// This location is used by clients rendering diagnostics.
- virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
-
- /// Get the location on which the report should be uniqued.
- PathDiagnosticLocation getUniqueingLocation() const {
- return UniqueingLocation;
- }
-
- /// Get the declaration containing the uniqueing location.
- const Decl *getUniqueingDecl() const {
- return UniqueingDecl;
- }
-
- const Stmt *getStmt() const;
-
- /// Add a range to a bug report.
- ///
- /// Ranges are used to highlight regions of interest in the source code.
- /// They should be at the same source code line as the BugReport location.
- /// By default, the source range of the statement corresponding to the error
- /// node will be used; add a single invalid range to specify absence of
- /// ranges.
- void addRange(SourceRange R) {
- assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
- "to specify that the report does not have a range.");
- Ranges.push_back(R);
- }
-
- /// Get the SourceRanges associated with the report.
- virtual llvm::iterator_range<ranges_iterator> getRanges();
+ /// Profile to identify equivalent bug reports for error report coalescing.
+ /// Reports are uniqued to ensure that we do not emit multiple diagnostics
+ /// for each bug.
+ void Profile(llvm::FoldingSetNodeID &hash) const override;
/// Add custom or predefined bug report visitors to this report.
///
@@ -351,6 +499,7 @@ public:
/// Iterators through the custom diagnostic visitors.
visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_iterator visitor_end() { return Callbacks.end(); }
+ visitor_range visitors() { return {visitor_begin(), visitor_end()}; }
/// Notes that the condition of the CFGBlock associated with \p Cond is
/// being tracked.
@@ -359,10 +508,25 @@ public:
return TrackedConditions.insert(Cond).second;
}
- /// Profile to identify equivalent bug reports for error report coalescing.
- /// Reports are uniqued to ensure that we do not emit multiple diagnostics
- /// for each bug.
- virtual void Profile(llvm::FoldingSetNodeID& hash) const;
+ void addCallStackHint(PathDiagnosticPieceRef Piece,
+ std::unique_ptr<StackHintGenerator> StackHint) {
+ StackHints[Piece] = std::move(StackHint);
+ }
+
+ bool hasCallStackHint(PathDiagnosticPieceRef Piece) const {
+ return StackHints.count(Piece) > 0;
+ }
+
+ /// Produce the hint for the given node. The node contains
+ /// information about the call for which the diagnostic can be generated.
+ std::string
+ getCallStackMessage(PathDiagnosticPieceRef Piece,
+ const ExplodedNode *N) const {
+ auto I = StackHints.find(Piece);
+ if (I != StackHints.end())
+ return I->second->getMessage(N);
+ return "";
+ }
};
//===----------------------------------------------------------------------===//
@@ -373,29 +537,21 @@ class BugReportEquivClass : public llvm::FoldingSetNode {
friend class BugReporter;
/// List of *owned* BugReport objects.
- llvm::ilist<BugReport> Reports;
+ llvm::SmallVector<std::unique_ptr<BugReport>, 4> Reports;
- void AddReport(std::unique_ptr<BugReport> R) {
- Reports.push_back(R.release());
+ void AddReport(std::unique_ptr<BugReport> &&R) {
+ Reports.push_back(std::move(R));
}
public:
BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); }
- ~BugReportEquivClass();
+
+ ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; }
void Profile(llvm::FoldingSetNodeID& ID) const {
assert(!Reports.empty());
- Reports.front().Profile(ID);
+ Reports.front()->Profile(ID);
}
-
- using iterator = llvm::ilist<BugReport>::iterator;
- using const_iterator = llvm::ilist<BugReport>::const_iterator;
-
- iterator begin() { return Reports.begin(); }
- iterator end() { return Reports.end(); }
-
- const_iterator begin() const { return Reports.begin(); }
- const_iterator end() const { return Reports.end(); }
};
//===----------------------------------------------------------------------===//
@@ -404,9 +560,8 @@ public:
class BugReporterData {
public:
- virtual ~BugReporterData();
+ virtual ~BugReporterData() = default;
- virtual DiagnosticsEngine& getDiagnostic() = 0;
virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0;
virtual ASTContext &getASTContext() = 0;
virtual SourceManager &getSourceManager() = 0;
@@ -419,60 +574,29 @@ public:
///
/// The base class is used for generating path-insensitive
class BugReporter {
-public:
- enum Kind { BaseBRKind, GRBugReporterKind };
-
private:
- using BugTypesTy = llvm::ImmutableSet<BugType *>;
-
- BugTypesTy::Factory F;
- BugTypesTy BugTypes;
-
- const Kind kind;
BugReporterData& D;
/// Generate and flush the diagnostics for the given bug report.
void FlushReport(BugReportEquivClass& EQ);
- /// Generate the diagnostics for the given bug report.
- std::unique_ptr<DiagnosticForConsumerMapTy>
- generateDiagnosticForConsumerMap(BugReport *exampleReport,
- ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> bugReports);
-
/// The set of bug reports tracked by the BugReporter.
llvm::FoldingSet<BugReportEquivClass> EQClasses;
/// A vector of BugReports for tracking the allocated pointers and cleanup.
std::vector<BugReportEquivClass *> EQClassesVector;
-protected:
- BugReporter(BugReporterData& d, Kind k)
- : BugTypes(F.getEmptySet()), kind(k), D(d) {}
-
public:
- BugReporter(BugReporterData& d)
- : BugTypes(F.getEmptySet()), kind(BaseBRKind), D(d) {}
+ BugReporter(BugReporterData &d) : D(d) {}
virtual ~BugReporter();
/// Generate and flush diagnostics for all bug reports.
void FlushReports();
- Kind getKind() const { return kind; }
-
- DiagnosticsEngine& getDiagnostic() {
- return D.getDiagnostic();
- }
-
ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() {
return D.getPathDiagnosticConsumers();
}
- /// Iterator over the set of BugTypes tracked by the BugReporter.
- using iterator = BugTypesTy::iterator;
- iterator begin() { return BugTypes.begin(); }
- iterator end() { return BugTypes.end(); }
-
/// Iterator over the set of BugReports tracked by the BugReporter.
using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator;
EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
@@ -480,126 +604,116 @@ public:
ASTContext &getContext() { return D.getASTContext(); }
- SourceManager &getSourceManager() { return D.getSourceManager(); }
-
- AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
-
- virtual std::unique_ptr<DiagnosticForConsumerMapTy>
- generatePathDiagnostics(ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> &bugReports) {
- return {};
- }
+ const SourceManager &getSourceManager() { return D.getSourceManager(); }
- void Register(const BugType *BT);
+ const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
/// Add the given report to the set of reports tracked by BugReporter.
///
/// The reports are usually generated by the checkers. Further, they are
/// folded based on the profile value, which is done to coalesce similar
/// reports.
- void emitReport(std::unique_ptr<BugReport> R);
+ virtual void emitReport(std::unique_ptr<BugReport> R);
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker,
StringRef BugName, StringRef BugCategory,
StringRef BugStr, PathDiagnosticLocation Loc,
- ArrayRef<SourceRange> Ranges = None);
+ ArrayRef<SourceRange> Ranges = None,
+ ArrayRef<FixItHint> Fixits = None);
- void EmitBasicReport(const Decl *DeclWithIssue, CheckName CheckName,
+ void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName,
StringRef BugName, StringRef BugCategory,
StringRef BugStr, PathDiagnosticLocation Loc,
- ArrayRef<SourceRange> Ranges = None);
+ ArrayRef<SourceRange> Ranges = None,
+ ArrayRef<FixItHint> Fixits = None);
private:
llvm::StringMap<BugType *> StrBugTypes;
/// Returns a BugType that is associated with the given name and
/// category.
- BugType *getBugTypeForName(CheckName CheckName, StringRef name,
+ BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name,
StringRef category);
+
+ virtual BugReport *
+ findReportInEquivalenceClass(BugReportEquivClass &eqClass,
+ SmallVectorImpl<BugReport *> &bugReports) {
+ return eqClass.getReports()[0].get();
+ }
+
+protected:
+ /// Generate the diagnostics for the given bug report.
+ virtual std::unique_ptr<DiagnosticForConsumerMapTy>
+ generateDiagnosticForConsumerMap(BugReport *exampleReport,
+ ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> bugReports);
};
/// GRBugReporter is used for generating path-sensitive reports.
-class GRBugReporter : public BugReporter {
+class PathSensitiveBugReporter final : public BugReporter {
ExprEngine& Eng;
-public:
- GRBugReporter(BugReporterData& d, ExprEngine& eng)
- : BugReporter(d, GRBugReporterKind), Eng(eng) {}
+ BugReport *findReportInEquivalenceClass(
+ BugReportEquivClass &eqClass,
+ SmallVectorImpl<BugReport *> &bugReports) override;
- ~GRBugReporter() override;
+ /// Generate the diagnostics for the given bug report.
+ std::unique_ptr<DiagnosticForConsumerMapTy>
+ generateDiagnosticForConsumerMap(BugReport *exampleReport,
+ ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> bugReports) override;
+public:
+ PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng)
+ : BugReporter(d), Eng(eng) {}
/// getGraph - Get the exploded graph created by the analysis engine
/// for the analyzed method or function.
- ExplodedGraph &getGraph();
+ const ExplodedGraph &getGraph() const;
/// getStateManager - Return the state manager used by the analysis
/// engine.
- ProgramStateManager &getStateManager();
+ ProgramStateManager &getStateManager() const;
/// \p bugReports A set of bug reports within a *single* equivalence class
///
/// \return A mapping from consumers to the corresponding diagnostics.
/// Iterates through the bug reports within a single equivalence class,
/// stops at a first non-invalidated report.
- std::unique_ptr<DiagnosticForConsumerMapTy>
- generatePathDiagnostics(ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> &bugReports) override;
+ std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics(
+ ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<PathSensitiveBugReport *> &bugReports);
- /// classof - Used by isa<>, cast<>, and dyn_cast<>.
- static bool classof(const BugReporter* R) {
- return R->getKind() == GRBugReporterKind;
- }
+ void emitReport(std::unique_ptr<BugReport> R) override;
};
-class NodeMapClosure : public BugReport::NodeResolver {
- InterExplodedGraphMap &M;
-
-public:
- NodeMapClosure(InterExplodedGraphMap &m) : M(m) {}
-
- const ExplodedNode *getOriginalNode(const ExplodedNode *N) override {
- return M.lookup(N);
- }
-};
-
class BugReporterContext {
- GRBugReporter &BR;
- NodeMapClosure NMC;
+ PathSensitiveBugReporter &BR;
virtual void anchor();
public:
- BugReporterContext(GRBugReporter &br, InterExplodedGraphMap &Backmap)
- : BR(br), NMC(Backmap) {}
+ BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {}
virtual ~BugReporterContext() = default;
- GRBugReporter& getBugReporter() { return BR; }
+ PathSensitiveBugReporter& getBugReporter() { return BR; }
- ExplodedGraph &getGraph() { return BR.getGraph(); }
-
- ProgramStateManager& getStateManager() {
+ ProgramStateManager& getStateManager() const {
return BR.getStateManager();
}
- SValBuilder &getSValBuilder() {
- return getStateManager().getSValBuilder();
- }
-
- ASTContext &getASTContext() {
+ ASTContext &getASTContext() const {
return BR.getContext();
}
- SourceManager& getSourceManager() {
+ const SourceManager& getSourceManager() const {
return BR.getSourceManager();
}
- AnalyzerOptions &getAnalyzerOptions() {
+ const AnalyzerOptions &getAnalyzerOptions() const {
return BR.getAnalyzerOptions();
}
-
- NodeMapClosure& getNodeResolver() { return NMC; }
};
@@ -648,7 +762,7 @@ public:
public:
const NoteTag *makeNoteTag(Callback &&Cb, bool IsPrunable = false) {
- // We cannot use make_unique because we cannot access the private
+ // We cannot use std::make_unique because we cannot access the private
// constructor from inside it.
std::unique_ptr<NoteTag> T(new NoteTag(std::move(Cb), IsPrunable));
Tags.push_back(std::move(T));
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index ef5d327d39da..de0ee5de81b5 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -33,11 +33,12 @@ class Stmt;
namespace ento {
-class BugReport;
+class PathSensitiveBugReport;
class BugReporterContext;
class ExplodedNode;
class MemRegion;
class PathDiagnosticPiece;
+using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
/// BugReporterVisitors are used to add custom diagnostics along a path.
class BugReporterVisitor : public llvm::FoldingSetNode {
@@ -57,32 +58,68 @@ public:
///
/// The last parameter can be used to register a new visitor with the given
/// BugReport while processing a node.
- virtual std::shared_ptr<PathDiagnosticPiece>
- VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC, BugReport &BR) = 0;
+ virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) = 0;
/// Last function called on the visitor, no further calls to VisitNode
/// would follow.
virtual void finalizeVisitor(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
- BugReport &BR);
+ PathSensitiveBugReport &BR);
/// Provide custom definition for the final diagnostic piece on the
/// path - the piece, which is displayed before the path is expanded.
///
/// NOTE that this function can be implemented on at most one used visitor,
/// and otherwise it crahes at runtime.
- virtual std::shared_ptr<PathDiagnosticPiece>
- getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR);
+ virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ PathSensitiveBugReport &BR);
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
/// Generates the default final diagnostic piece.
- static std::shared_ptr<PathDiagnosticPiece>
- getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N,
- BugReport &BR);
+ static PathDiagnosticPieceRef
+ getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N,
+ const PathSensitiveBugReport &BR);
};
+namespace bugreporter {
+
+/// Specifies the type of tracking for an expression.
+enum class TrackingKind {
+ /// Default tracking kind -- specifies that as much information should be
+ /// gathered about the tracked expression value as possible.
+ Thorough,
+ /// Specifies that a more moderate tracking should be used for the expression
+ /// value. This will essentially make sure that functions relevant to the it
+ /// aren't pruned, but otherwise relies on the user reading the code or
+ /// following the arrows.
+ Condition
+};
+
+/// Attempts to add visitors to track expression value back to its point of
+/// origin.
+///
+/// \param N A node "downstream" from the evaluation of the statement.
+/// \param E The expression value which we are tracking
+/// \param R The bug report to which visitors should be attached.
+/// \param EnableNullFPSuppression Whether we should employ false positive
+/// suppression (inlined defensive checks, returned null).
+///
+/// \return Whether or not the function was able to add visitors for this
+/// statement. Note that returning \c true does not actually imply
+/// that any visitors were added.
+bool trackExpressionValue(const ExplodedNode *N, const Expr *E,
+ PathSensitiveBugReport &R,
+ TrackingKind TKind = TrackingKind::Thorough,
+ bool EnableNullFPSuppression = true);
+
+const Expr *getDerefExpr(const Stmt *S);
+
+} // namespace bugreporter
+
/// Finds last store into the given region,
/// which is different from a given symbolic value.
class FindLastStoreBRVisitor final : public BugReporterVisitor {
@@ -94,21 +131,34 @@ class FindLastStoreBRVisitor final : public BugReporterVisitor {
/// bug, we are going to employ false positive suppression.
bool EnableNullFPSuppression;
-public:
- /// Creates a visitor for every VarDecl inside a Stmt and registers it with
- /// the BugReport.
- static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
- bool EnableNullFPSuppression);
+ using TrackingKind = bugreporter::TrackingKind;
+ TrackingKind TKind;
+ const StackFrameContext *OriginSFC;
+public:
+ /// \param V We're searching for the store where \c R received this value.
+ /// \param R The region we're tracking.
+ /// \param TKind May limit the amount of notes added to the bug report.
+ /// \param OriginSFC Only adds notes when the last store happened in a
+ /// different stackframe to this one. Disregarded if the tracking kind
+ /// is thorough.
+ /// This is useful, because for non-tracked regions, notes about
+ /// changes to its value in a nested stackframe could be pruned, and
+ /// this visitor can prevent that without polluting the bugpath too
+ /// much.
FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
- bool InEnableNullFPSuppression)
- : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression) {}
+ bool InEnableNullFPSuppression, TrackingKind TKind,
+ const StackFrameContext *OriginSFC = nullptr)
+ : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression),
+ TKind(TKind), OriginSFC(OriginSFC) {
+ assert(R);
+ }
void Profile(llvm::FoldingSetNodeID &ID) const override;
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
class TrackConstraintBRVisitor final : public BugReporterVisitor {
@@ -132,9 +182,9 @@ public:
/// to make all PathDiagnosticPieces created by this visitor.
static const char *getTag();
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
/// Checks if the constraint is valid in the current state.
@@ -150,9 +200,9 @@ public:
ID.AddPointer(&x);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
/// If the statement is a message send expression with nil receiver, returns
/// the receiver expression. Returns NULL otherwise.
@@ -162,8 +212,10 @@ public:
/// Visitor that tries to report interesting diagnostics from conditions.
class ConditionBRVisitor final : public BugReporterVisitor {
// FIXME: constexpr initialization isn't supported by MSVC2013.
- static const char *const GenericTrueMessage;
- static const char *const GenericFalseMessage;
+ constexpr static llvm::StringLiteral GenericTrueMessage =
+ "Assuming the condition is true";
+ constexpr static llvm::StringLiteral GenericFalseMessage =
+ "Assuming the condition is false";
public:
void Profile(llvm::FoldingSetNodeID &ID) const override {
@@ -175,41 +227,44 @@ public:
/// to make all PathDiagnosticPieces created by this visitor.
static const char *getTag();
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
- std::shared_ptr<PathDiagnosticPiece> VisitNodeImpl(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR);
+ PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR);
- std::shared_ptr<PathDiagnosticPiece>
+ PathDiagnosticPieceRef
VisitTerminator(const Stmt *Term, const ExplodedNode *N,
- const CFGBlock *srcBlk, const CFGBlock *dstBlk, BugReport &R,
- BugReporterContext &BRC);
+ const CFGBlock *SrcBlk, const CFGBlock *DstBlk,
+ PathSensitiveBugReport &R, BugReporterContext &BRC);
- std::shared_ptr<PathDiagnosticPiece>
- VisitTrueTest(const Expr *Cond, BugReporterContext &BRC, BugReport &R,
- const ExplodedNode *N, bool TookTrue);
+ PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue);
- std::shared_ptr<PathDiagnosticPiece>
- VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
- BugReporterContext &BRC, BugReport &R, const ExplodedNode *N,
- bool TookTrue, bool IsAssuming);
+ PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming);
- std::shared_ptr<PathDiagnosticPiece>
+ PathDiagnosticPieceRef
VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
- BugReporterContext &BRC, BugReport &R, const ExplodedNode *N,
- bool TookTrue, bool IsAssuming);
+ BugReporterContext &BRC, PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue, bool IsAssuming);
- std::shared_ptr<PathDiagnosticPiece>
- VisitTrueTest(const Expr *Cond, const MemberExpr *ME, BugReporterContext &BRC,
- BugReport &R, const ExplodedNode *N, bool TookTrue,
- bool IsAssuming);
+ PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming);
- std::shared_ptr<PathDiagnosticPiece>
+ PathDiagnosticPieceRef
VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
- BugReporterContext &BRC, BugReport &R,
+ BugReporterContext &BRC, PathSensitiveBugReport &R,
const ExplodedNode *N, bool TookTrue);
/// Tries to print the value of the given expression.
@@ -228,7 +283,7 @@ public:
const Expr *ParentEx,
raw_ostream &Out,
BugReporterContext &BRC,
- BugReport &R,
+ PathSensitiveBugReport &R,
const ExplodedNode *N,
Optional<bool> &prunable,
bool IsSameFieldName);
@@ -251,14 +306,13 @@ public:
ID.AddPointer(getTag());
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *,
- BugReporterContext &,
- BugReport &) override {
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &,
+ PathSensitiveBugReport &) override {
return nullptr;
}
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
- BugReport &BR) override;
+ PathSensitiveBugReport &BR) override;
};
/// When a region containing undefined value or '0' value is passed
@@ -279,9 +333,9 @@ public:
ID.AddPointer(R);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
@@ -308,9 +362,9 @@ public:
/// to make all PathDiagnosticPieces created by this visitor.
static const char *getTag();
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
/// The bug visitor will walk all the nodes in a path and collect all the
@@ -326,12 +380,12 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
- BugReport &BR) override;
+ PathSensitiveBugReport &BR) override;
};
@@ -340,32 +394,11 @@ class TagVisitor : public BugReporterVisitor {
public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &R) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R) override;
};
-namespace bugreporter {
-
-/// Attempts to add visitors to track expression value back to its point of
-/// origin.
-///
-/// \param N A node "downstream" from the evaluation of the statement.
-/// \param E The expression value which we are tracking
-/// \param R The bug report to which visitors should be attached.
-/// \param EnableNullFPSuppression Whether we should employ false positive
-/// suppression (inlined defensive checks, returned null).
-///
-/// \return Whether or not the function was able to add visitors for this
-/// statement. Note that returning \c true does not actually imply
-/// that any visitors were added.
-bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R,
- bool EnableNullFPSuppression = true);
-
-const Expr *getDerefExpr(const Stmt *S);
-
-} // namespace bugreporter
-
} // namespace ento
} // namespace clang
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 324b5312e790..237053df7e44 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -28,8 +28,8 @@ class ExprEngine;
class BugType {
private:
- const CheckName Check;
- const std::string Name;
+ const CheckerNameRef CheckerName;
+ const std::string Description;
const std::string Category;
const CheckerBase *Checker;
bool SuppressOnSink;
@@ -37,28 +37,27 @@ private:
virtual void anchor();
public:
- BugType(CheckName Check, StringRef Name, StringRef Cat,
- bool SuppressOnSink=false)
- : Check(Check), Name(Name), Category(Cat), Checker(nullptr),
- SuppressOnSink(SuppressOnSink) {}
+ BugType(CheckerNameRef CheckerName, StringRef Name, StringRef Cat,
+ bool SuppressOnSink = false)
+ : CheckerName(CheckerName), Description(Name), Category(Cat),
+ Checker(nullptr), SuppressOnSink(SuppressOnSink) {}
BugType(const CheckerBase *Checker, StringRef Name, StringRef Cat,
- bool SuppressOnSink=false)
- : Check(Checker->getCheckName()), Name(Name), Category(Cat),
- Checker(Checker), SuppressOnSink(SuppressOnSink) {}
+ bool SuppressOnSink = false)
+ : CheckerName(Checker->getCheckerName()), Description(Name),
+ Category(Cat), Checker(Checker), SuppressOnSink(SuppressOnSink) {}
virtual ~BugType() = default;
- StringRef getName() const { return Name; }
+ StringRef getDescription() const { return Description; }
StringRef getCategory() const { return Category; }
- StringRef getCheckName() const {
- // FIXME: This is a workaround to ensure that the correct check name is used
- // The check names are set after the constructors are run.
+ StringRef getCheckerName() const {
+ // FIXME: This is a workaround to ensure that the correct checerk name is
+ // used. The checker names are set after the constructors are run.
// In case the BugType object is initialized in the checker's ctor
- // the Check field will be empty. To circumvent this problem we use
+ // the CheckerName field will be empty. To circumvent this problem we use
// CheckerBase whenever it is possible.
- StringRef CheckName =
- Checker ? Checker->getCheckName().getName() : Check.getName();
- assert(!CheckName.empty() && "Check name is not set properly.");
- return CheckName;
+ StringRef Ret = Checker ? Checker->getCheckerName() : CheckerName;
+ assert(!Ret.empty() && "Checker name is not set properly.");
+ return Ret;
}
/// isSuppressOnSink - Returns true if bug reports associated with this bug
@@ -71,8 +70,9 @@ class BuiltinBug : public BugType {
const std::string desc;
void anchor() override;
public:
- BuiltinBug(class CheckName check, const char *name, const char *description)
- : BugType(check, name, categories::LogicError), desc(description) {}
+ BuiltinBug(class CheckerNameRef checker, const char *name,
+ const char *description)
+ : BugType(checker, name, categories::LogicError), desc(description) {}
BuiltinBug(const CheckerBase *checker, const char *name,
const char *description)
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
index 85526eb49f0c..22c1a7dd98cc 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
@@ -18,6 +18,7 @@ namespace clang {
extern const char * const MemoryRefCount;
extern const char * const MemoryError;
extern const char * const UnixAPI;
+ extern const char * const CXXObjectLifecycle;
}
}
}
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
deleted file mode 100644
index 5230742a4aa4..000000000000
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ /dev/null
@@ -1,923 +0,0 @@
-//===- PathDiagnostic.h - Path-Specific Diagnostic Handling -----*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the PathDiagnostic-related interfaces.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
-#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
-
-#include "clang/AST/Stmt.h"
-#include "clang/Analysis/AnalysisDeclContext.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Allocator.h"
-#include <cassert>
-#include <deque>
-#include <iterator>
-#include <list>
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-namespace clang {
-
-class AnalysisDeclContext;
-class BinaryOperator;
-class CallEnter;
-class CallExitEnd;
-class CallExpr;
-class ConditionalOperator;
-class Decl;
-class Expr;
-class LocationContext;
-class MemberExpr;
-class ProgramPoint;
-class SourceManager;
-
-namespace ento {
-
-class ExplodedNode;
-class SymExpr;
-
-using SymbolRef = const SymExpr *;
-
-//===----------------------------------------------------------------------===//
-// High-level interface for handlers of path-sensitive diagnostics.
-//===----------------------------------------------------------------------===//
-
-class PathDiagnostic;
-
-class PathDiagnosticConsumer {
-public:
- class PDFileEntry : public llvm::FoldingSetNode {
- public:
- PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
-
- using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
-
- /// A vector of <consumer,file> pairs.
- ConsumerFiles files;
-
- /// A precomputed hash tag used for uniquing PDFileEntry objects.
- const llvm::FoldingSetNodeID NodeID;
-
- /// Used for profiling in the FoldingSet.
- void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
- };
-
- class FilesMade {
- llvm::BumpPtrAllocator Alloc;
- llvm::FoldingSet<PDFileEntry> Set;
-
- public:
- ~FilesMade();
-
- bool empty() const { return Set.empty(); }
-
- void addDiagnostic(const PathDiagnostic &PD,
- StringRef ConsumerName,
- StringRef fileName);
-
- PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
- };
-
-private:
- virtual void anchor();
-
-public:
- PathDiagnosticConsumer() = default;
- virtual ~PathDiagnosticConsumer();
-
- void FlushDiagnostics(FilesMade *FilesMade);
-
- virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
- FilesMade *filesMade) = 0;
-
- virtual StringRef getName() const = 0;
-
- void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
-
- enum PathGenerationScheme {
- /// Only runs visitors, no output generated.
- None,
-
- /// Used for HTML, SARIF, and text output.
- Minimal,
-
- /// Used for plist output, used for "arrows" generation.
- Extensive,
- };
-
- virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
- virtual bool supportsLogicalOpControlFlow() const { return false; }
-
- /// Return true if the PathDiagnosticConsumer supports individual
- /// PathDiagnostics that span multiple files.
- virtual bool supportsCrossFileDiagnostics() const { return false; }
-
-protected:
- bool flushed = false;
- llvm::FoldingSet<PathDiagnostic> Diags;
-};
-
-//===----------------------------------------------------------------------===//
-// Path-sensitive diagnostics.
-//===----------------------------------------------------------------------===//
-
-class PathDiagnosticRange : public SourceRange {
-public:
- bool isPoint = false;
-
- PathDiagnosticRange(SourceRange R, bool isP = false)
- : SourceRange(R), isPoint(isP) {}
- PathDiagnosticRange() = default;
-};
-
-using LocationOrAnalysisDeclContext =
- llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
-
-class PathDiagnosticLocation {
-private:
- enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
-
- const Stmt *S = nullptr;
- const Decl *D = nullptr;
- const SourceManager *SM = nullptr;
- FullSourceLoc Loc;
- PathDiagnosticRange Range;
-
- PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
- : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
-
- FullSourceLoc genLocation(
- SourceLocation L = SourceLocation(),
- LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
-
- PathDiagnosticRange genRange(
- LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
-
-public:
- /// Create an invalid location.
- PathDiagnosticLocation() = default;
-
- /// Create a location corresponding to the given statement.
- PathDiagnosticLocation(const Stmt *s, const SourceManager &sm,
- LocationOrAnalysisDeclContext lac)
- : K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
- S(K == StmtK ? s : nullptr), SM(&sm),
- Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
- assert(K == SingleLocK || S);
- assert(K == SingleLocK || Loc.isValid());
- assert(K == SingleLocK || Range.isValid());
- }
-
- /// Create a location corresponding to the given declaration.
- PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
- : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
- assert(D);
- assert(Loc.isValid());
- assert(Range.isValid());
- }
-
- /// Create a location at an explicit offset in the source.
- ///
- /// This should only be used if there are no more appropriate constructors.
- PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
- : SM(&sm), Loc(loc, sm), Range(genRange()) {
- assert(Loc.isValid());
- assert(Range.isValid());
- }
-
- /// Create a location corresponding to the given declaration.
- static PathDiagnosticLocation create(const Decl *D,
- const SourceManager &SM) {
- return PathDiagnosticLocation(D, SM);
- }
-
- /// Create a location for the beginning of the declaration.
- static PathDiagnosticLocation createBegin(const Decl *D,
- const SourceManager &SM);
-
- /// Create a location for the beginning of the declaration.
- /// The third argument is ignored, useful for generic treatment
- /// of statements and declarations.
- static PathDiagnosticLocation
- createBegin(const Decl *D, const SourceManager &SM,
- const LocationOrAnalysisDeclContext LAC) {
- return createBegin(D, SM);
- }
-
- /// Create a location for the beginning of the statement.
- static PathDiagnosticLocation createBegin(const Stmt *S,
- const SourceManager &SM,
- const LocationOrAnalysisDeclContext LAC);
-
- /// Create a location for the end of the statement.
- ///
- /// If the statement is a CompoundStatement, the location will point to the
- /// closing brace instead of following it.
- static PathDiagnosticLocation createEnd(const Stmt *S,
- const SourceManager &SM,
- const LocationOrAnalysisDeclContext LAC);
-
- /// Create the location for the operator of the binary expression.
- /// Assumes the statement has a valid location.
- static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
- const SourceManager &SM);
- static PathDiagnosticLocation createConditionalColonLoc(
- const ConditionalOperator *CO,
- const SourceManager &SM);
-
- /// For member expressions, return the location of the '.' or '->'.
- /// Assumes the statement has a valid location.
- static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
- const SourceManager &SM);
-
- /// Create a location for the beginning of the compound statement.
- /// Assumes the statement has a valid location.
- static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
- const SourceManager &SM);
-
- /// Create a location for the end of the compound statement.
- /// Assumes the statement has a valid location.
- static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
- const SourceManager &SM);
-
- /// Create a location for the beginning of the enclosing declaration body.
- /// Defaults to the beginning of the first statement in the declaration body.
- static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
- const SourceManager &SM);
-
- /// Constructs a location for the end of the enclosing declaration body.
- /// Defaults to the end of brace.
- static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
- const SourceManager &SM);
-
- /// Create a location corresponding to the given valid ExplodedNode.
- static PathDiagnosticLocation create(const ProgramPoint &P,
- const SourceManager &SMng);
-
- /// Create a location corresponding to the next valid ExplodedNode as end
- /// of path location.
- static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
- const SourceManager &SM);
-
- /// Convert the given location into a single kind location.
- static PathDiagnosticLocation createSingleLocation(
- const PathDiagnosticLocation &PDL);
-
- bool operator==(const PathDiagnosticLocation &X) const {
- return K == X.K && Loc == X.Loc && Range == X.Range;
- }
-
- bool operator!=(const PathDiagnosticLocation &X) const {
- return !(*this == X);
- }
-
- bool isValid() const {
- return SM != nullptr;
- }
-
- FullSourceLoc asLocation() const {
- return Loc;
- }
-
- PathDiagnosticRange asRange() const {
- return Range;
- }
-
- const Stmt *asStmt() const { assert(isValid()); return S; }
- const Stmt *getStmtOrNull() const {
- if (!isValid())
- return nullptr;
- return asStmt();
- }
-
- const Decl *asDecl() const { assert(isValid()); return D; }
-
- bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
-
- bool hasValidLocation() const { return asLocation().isValid(); }
-
- void invalidate() {
- *this = PathDiagnosticLocation();
- }
-
- void flatten();
-
- const SourceManager& getManager() const { assert(isValid()); return *SM; }
-
- void Profile(llvm::FoldingSetNodeID &ID) const;
-
- void dump() const;
-
- /// Given an exploded node, retrieve the statement that should be used
- /// for the diagnostic location.
- static const Stmt *getStmt(const ExplodedNode *N);
-
- /// Retrieve the statement corresponding to the successor node.
- static const Stmt *getNextStmt(const ExplodedNode *N);
-};
-
-class PathDiagnosticLocationPair {
-private:
- PathDiagnosticLocation Start, End;
-
-public:
- PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
- const PathDiagnosticLocation &end)
- : Start(start), End(end) {}
-
- const PathDiagnosticLocation &getStart() const { return Start; }
- const PathDiagnosticLocation &getEnd() const { return End; }
-
- void setStart(const PathDiagnosticLocation &L) { Start = L; }
- void setEnd(const PathDiagnosticLocation &L) { End = L; }
-
- void flatten() {
- Start.flatten();
- End.flatten();
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- Start.Profile(ID);
- End.Profile(ID);
- }
-};
-
-//===----------------------------------------------------------------------===//
-// Path "pieces" for path-sensitive diagnostics.
-//===----------------------------------------------------------------------===//
-
-class PathDiagnosticPiece: public llvm::FoldingSetNode {
-public:
- enum Kind { ControlFlow, Event, Macro, Call, Note, PopUp };
- enum DisplayHint { Above, Below };
-
-private:
- const std::string str;
- const Kind kind;
- const DisplayHint Hint;
-
- /// In the containing bug report, this piece is the last piece from
- /// the main source file.
- bool LastInMainSourceFile = false;
-
- /// A constant string that can be used to tag the PathDiagnosticPiece,
- /// typically with the identification of the creator. The actual pointer
- /// value is meant to be an identifier; the string itself is useful for
- /// debugging.
- StringRef Tag;
-
- std::vector<SourceRange> ranges;
-
-protected:
- PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
- PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
-
-public:
- PathDiagnosticPiece() = delete;
- PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
- PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
- virtual ~PathDiagnosticPiece();
-
- StringRef getString() const { return str; }
-
- /// Tag this PathDiagnosticPiece with the given C-string.
- void setTag(const char *tag) { Tag = tag; }
-
- /// Return the opaque tag (if any) on the PathDiagnosticPiece.
- const void *getTag() const { return Tag.data(); }
-
- /// Return the string representation of the tag. This is useful
- /// for debugging.
- StringRef getTagStr() const { return Tag; }
-
- /// getDisplayHint - Return a hint indicating where the diagnostic should
- /// be displayed by the PathDiagnosticConsumer.
- DisplayHint getDisplayHint() const { return Hint; }
-
- virtual PathDiagnosticLocation getLocation() const = 0;
- virtual void flattenLocations() = 0;
-
- Kind getKind() const { return kind; }
-
- void addRange(SourceRange R) {
- if (!R.isValid())
- return;
- ranges.push_back(R);
- }
-
- void addRange(SourceLocation B, SourceLocation E) {
- if (!B.isValid() || !E.isValid())
- return;
- ranges.push_back(SourceRange(B,E));
- }
-
- /// Return the SourceRanges associated with this PathDiagnosticPiece.
- ArrayRef<SourceRange> getRanges() const { return ranges; }
-
- virtual void Profile(llvm::FoldingSetNodeID &ID) const;
-
- void setAsLastInMainSourceFile() {
- LastInMainSourceFile = true;
- }
-
- bool isLastInMainSourceFile() const {
- return LastInMainSourceFile;
- }
-
- virtual void dump() const = 0;
-};
-
-class PathPieces : public std::list<std::shared_ptr<PathDiagnosticPiece>> {
- void flattenTo(PathPieces &Primary, PathPieces &Current,
- bool ShouldFlattenMacros) const;
-
-public:
- PathPieces flatten(bool ShouldFlattenMacros) const {
- PathPieces Result;
- flattenTo(Result, Result, ShouldFlattenMacros);
- return Result;
- }
-
- void dump() const;
-};
-
-class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
-private:
- PathDiagnosticLocation Pos;
-
-public:
- PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
- StringRef s,
- PathDiagnosticPiece::Kind k,
- bool addPosRange = true)
- : PathDiagnosticPiece(s, k), Pos(pos) {
- assert(Pos.isValid() && Pos.hasValidLocation() &&
- "PathDiagnosticSpotPiece's must have a valid location.");
- if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
- }
-
- PathDiagnosticLocation getLocation() const override { return Pos; }
- void flattenLocations() override { Pos.flatten(); }
-
- void Profile(llvm::FoldingSetNodeID &ID) const override;
-
- static bool classof(const PathDiagnosticPiece *P) {
- return P->getKind() == Event || P->getKind() == Macro ||
- P->getKind() == Note || P->getKind() == PopUp;
- }
-};
-
-/// Interface for classes constructing Stack hints.
-///
-/// If a PathDiagnosticEvent occurs in a different frame than the final
-/// diagnostic the hints can be used to summarize the effect of the call.
-class StackHintGenerator {
-public:
- virtual ~StackHintGenerator() = 0;
-
- /// Construct the Diagnostic message for the given ExplodedNode.
- virtual std::string getMessage(const ExplodedNode *N) = 0;
-};
-
-/// Constructs a Stack hint for the given symbol.
-///
-/// The class knows how to construct the stack hint message based on
-/// traversing the CallExpr associated with the call and checking if the given
-/// symbol is returned or is one of the arguments.
-/// The hint can be customized by redefining 'getMessageForX()' methods.
-class StackHintGeneratorForSymbol : public StackHintGenerator {
-private:
- SymbolRef Sym;
- std::string Msg;
-
-public:
- StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
- ~StackHintGeneratorForSymbol() override = default;
-
- /// Search the call expression for the symbol Sym and dispatch the
- /// 'getMessageForX()' methods to construct a specific message.
- std::string getMessage(const ExplodedNode *N) override;
-
- /// Produces the message of the following form:
- /// 'Msg via Nth parameter'
- virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
-
- virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
- return Msg;
- }
-
- virtual std::string getMessageForSymbolNotFound() {
- return Msg;
- }
-};
-
-class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
- Optional<bool> IsPrunable;
-
- /// If the event occurs in a different frame than the final diagnostic,
- /// supply a message that will be used to construct an extra hint on the
- /// returns from all the calls on the stack from this event to the final
- /// diagnostic.
- std::unique_ptr<StackHintGenerator> CallStackHint;
-
-public:
- PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
- StringRef s, bool addPosRange = true,
- StackHintGenerator *stackHint = nullptr)
- : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
- CallStackHint(stackHint) {}
- ~PathDiagnosticEventPiece() override;
-
- /// Mark the diagnostic piece as being potentially prunable. This
- /// flag may have been previously set, at which point it will not
- /// be reset unless one specifies to do so.
- void setPrunable(bool isPrunable, bool override = false) {
- if (IsPrunable.hasValue() && !override)
- return;
- IsPrunable = isPrunable;
- }
-
- /// Return true if the diagnostic piece is prunable.
- bool isPrunable() const {
- return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
- }
-
- bool hasCallStackHint() { return (bool)CallStackHint; }
-
- /// Produce the hint for the given node. The node contains
- /// information about the call for which the diagnostic can be generated.
- std::string getCallStackMessage(const ExplodedNode *N) {
- if (CallStackHint)
- return CallStackHint->getMessage(N);
- return {};
- }
-
- void dump() const override;
-
- static bool classof(const PathDiagnosticPiece *P) {
- return P->getKind() == Event;
- }
-};
-
-class PathDiagnosticCallPiece : public PathDiagnosticPiece {
- const Decl *Caller;
- const Decl *Callee = nullptr;
-
- // Flag signifying that this diagnostic has only call enter and no matching
- // call exit.
- bool NoExit;
-
- // Flag signifying that the callee function is an Objective-C autosynthesized
- // property getter or setter.
- bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
-
- // The custom string, which should appear after the call Return Diagnostic.
- // TODO: Should we allow multiple diagnostics?
- std::string CallStackMessage;
-
- PathDiagnosticCallPiece(const Decl *callerD,
- const PathDiagnosticLocation &callReturnPos)
- : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
- callReturn(callReturnPos) {}
- PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
- : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
- path(oldPath) {}
-
-public:
- PathDiagnosticLocation callEnter;
- PathDiagnosticLocation callEnterWithin;
- PathDiagnosticLocation callReturn;
- PathPieces path;
-
- ~PathDiagnosticCallPiece() override;
-
- const Decl *getCaller() const { return Caller; }
-
- const Decl *getCallee() const { return Callee; }
- void setCallee(const CallEnter &CE, const SourceManager &SM);
-
- bool hasCallStackMessage() { return !CallStackMessage.empty(); }
- void setCallStackMessage(StringRef st) { CallStackMessage = st; }
-
- PathDiagnosticLocation getLocation() const override { return callEnter; }
-
- std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
- std::shared_ptr<PathDiagnosticEventPiece>
- getCallEnterWithinCallerEvent() const;
- std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
-
- void flattenLocations() override {
- callEnter.flatten();
- callReturn.flatten();
- for (const auto &I : path)
- I->flattenLocations();
- }
-
- static std::shared_ptr<PathDiagnosticCallPiece>
- construct(const CallExitEnd &CE,
- const SourceManager &SM);
-
- static PathDiagnosticCallPiece *construct(PathPieces &pieces,
- const Decl *caller);
-
- void dump() const override;
-
- void Profile(llvm::FoldingSetNodeID &ID) const override;
-
- static bool classof(const PathDiagnosticPiece *P) {
- return P->getKind() == Call;
- }
-};
-
-class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
- std::vector<PathDiagnosticLocationPair> LPairs;
-
-public:
- PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
- const PathDiagnosticLocation &endPos,
- StringRef s)
- : PathDiagnosticPiece(s, ControlFlow) {
- LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
- }
-
- PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
- const PathDiagnosticLocation &endPos)
- : PathDiagnosticPiece(ControlFlow) {
- LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
- }
-
- ~PathDiagnosticControlFlowPiece() override;
-
- PathDiagnosticLocation getStartLocation() const {
- assert(!LPairs.empty() &&
- "PathDiagnosticControlFlowPiece needs at least one location.");
- return LPairs[0].getStart();
- }
-
- PathDiagnosticLocation getEndLocation() const {
- assert(!LPairs.empty() &&
- "PathDiagnosticControlFlowPiece needs at least one location.");
- return LPairs[0].getEnd();
- }
-
- void setStartLocation(const PathDiagnosticLocation &L) {
- LPairs[0].setStart(L);
- }
-
- void setEndLocation(const PathDiagnosticLocation &L) {
- LPairs[0].setEnd(L);
- }
-
- void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
-
- PathDiagnosticLocation getLocation() const override {
- return getStartLocation();
- }
-
- using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
-
- iterator begin() { return LPairs.begin(); }
- iterator end() { return LPairs.end(); }
-
- void flattenLocations() override {
- for (auto &I : *this)
- I.flatten();
- }
-
- using const_iterator =
- std::vector<PathDiagnosticLocationPair>::const_iterator;
-
- const_iterator begin() const { return LPairs.begin(); }
- const_iterator end() const { return LPairs.end(); }
-
- static bool classof(const PathDiagnosticPiece *P) {
- return P->getKind() == ControlFlow;
- }
-
- void dump() const override;
-
- void Profile(llvm::FoldingSetNodeID &ID) const override;
-};
-
-class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
-public:
- PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
- : PathDiagnosticSpotPiece(pos, "", Macro) {}
- ~PathDiagnosticMacroPiece() override;
-
- PathPieces subPieces;
-
- bool containsEvent() const;
-
- void flattenLocations() override {
- PathDiagnosticSpotPiece::flattenLocations();
- for (const auto &I : subPieces)
- I->flattenLocations();
- }
-
- static bool classof(const PathDiagnosticPiece *P) {
- return P->getKind() == Macro;
- }
-
- void dump() const override;
-
- void Profile(llvm::FoldingSetNodeID &ID) const override;
-};
-
-class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
-public:
- PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
- bool AddPosRange = true)
- : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
- ~PathDiagnosticNotePiece() override;
-
- static bool classof(const PathDiagnosticPiece *P) {
- return P->getKind() == Note;
- }
-
- void dump() const override;
-
- void Profile(llvm::FoldingSetNodeID &ID) const override;
-};
-
-class PathDiagnosticPopUpPiece: public PathDiagnosticSpotPiece {
-public:
- PathDiagnosticPopUpPiece(const PathDiagnosticLocation &Pos, StringRef S,
- bool AddPosRange = true)
- : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
- ~PathDiagnosticPopUpPiece() override;
-
- static bool classof(const PathDiagnosticPiece *P) {
- return P->getKind() == PopUp;
- }
-
- void dump() const override;
-
- void Profile(llvm::FoldingSetNodeID &ID) const override;
-};
-
-/// File IDs mapped to sets of line numbers.
-using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
-
-/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
-/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
-/// each which represent the pieces of the path.
-class PathDiagnostic : public llvm::FoldingSetNode {
- std::string CheckName;
- const Decl *DeclWithIssue;
- std::string BugType;
- std::string VerboseDesc;
- std::string ShortDesc;
- std::string Category;
- std::deque<std::string> OtherDesc;
-
- /// Loc The location of the path diagnostic report.
- PathDiagnosticLocation Loc;
-
- PathPieces pathImpl;
- SmallVector<PathPieces *, 3> pathStack;
-
- /// Important bug uniqueing location.
- /// The location info is useful to differentiate between bugs.
- PathDiagnosticLocation UniqueingLoc;
- const Decl *UniqueingDecl;
-
- /// Lines executed in the path.
- std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
-
-public:
- PathDiagnostic() = delete;
- PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue,
- StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
- StringRef category, PathDiagnosticLocation LocationToUnique,
- const Decl *DeclToUnique,
- std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
- ~PathDiagnostic();
-
- const PathPieces &path;
-
- /// Return the path currently used by builders for constructing the
- /// PathDiagnostic.
- PathPieces &getActivePath() {
- if (pathStack.empty())
- return pathImpl;
- return *pathStack.back();
- }
-
- /// Return a mutable version of 'path'.
- PathPieces &getMutablePieces() {
- return pathImpl;
- }
-
- /// Return the unrolled size of the path.
- unsigned full_size();
-
- void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
- void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
-
- bool isWithinCall() const { return !pathStack.empty(); }
-
- void setEndOfPath(std::shared_ptr<PathDiagnosticPiece> EndPiece) {
- assert(!Loc.isValid() && "End location already set!");
- Loc = EndPiece->getLocation();
- assert(Loc.isValid() && "Invalid location for end-of-path piece");
- getActivePath().push_back(std::move(EndPiece));
- }
-
- void appendToDesc(StringRef S) {
- if (!ShortDesc.empty())
- ShortDesc += S;
- VerboseDesc += S;
- }
-
- /// If the last piece of the report point to the header file, resets
- /// the location of the report to be the last location in the main source
- /// file.
- void resetDiagnosticLocationToMainFile();
-
- StringRef getVerboseDescription() const { return VerboseDesc; }
-
- StringRef getShortDescription() const {
- return ShortDesc.empty() ? VerboseDesc : ShortDesc;
- }
-
- StringRef getCheckName() const { return CheckName; }
- StringRef getBugType() const { return BugType; }
- StringRef getCategory() const { return Category; }
-
- /// Return the semantic context where an issue occurred. If the
- /// issue occurs along a path, this represents the "central" area
- /// where the bug manifests.
- const Decl *getDeclWithIssue() const { return DeclWithIssue; }
-
- using meta_iterator = std::deque<std::string>::const_iterator;
-
- meta_iterator meta_begin() const { return OtherDesc.begin(); }
- meta_iterator meta_end() const { return OtherDesc.end(); }
- void addMeta(StringRef s) { OtherDesc.push_back(s); }
-
- const FilesToLineNumsMap &getExecutedLines() const {
- return *ExecutedLines;
- }
-
- FilesToLineNumsMap &getExecutedLines() {
- return *ExecutedLines;
- }
-
- PathDiagnosticLocation getLocation() const {
- return Loc;
- }
-
- /// Get the location on which the report should be uniqued.
- PathDiagnosticLocation getUniqueingLoc() const {
- return UniqueingLoc;
- }
-
- /// Get the declaration containing the uniqueing location.
- const Decl *getUniqueingDecl() const {
- return UniqueingDecl;
- }
-
- void flattenLocations() {
- Loc.flatten();
- for (const auto &I : pathImpl)
- I->flattenLocations();
- }
-
- /// Profiles the diagnostic, independent of the path it references.
- ///
- /// This can be used to merge diagnostics that refer to the same issue
- /// along different paths.
- void Profile(llvm::FoldingSetNodeID &ID) const;
-
- /// Profiles the diagnostic, including its path.
- ///
- /// Two diagnostics with the same issue along different paths will generate
- /// different profiles.
- void FullProfile(llvm::FoldingSetNodeID &ID) const;
-};
-
-} // namespace ento
-
-} // namespace clang
-
-#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H