summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2019-09-09 20:34:40 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2019-09-09 20:34:40 +0000
commit2f169e7cdd9973d2aa4cba6b0a09126a5e7268ec (patch)
tree583758bdf33ed6ba3d9780cd37cb30ebf977ee5e /clang/lib/StaticAnalyzer/Core
parent48453bb8eda3d25b50ab098ebdc33a08724b2e2f (diff)
downloadbcm5719-llvm-2f169e7cdd9973d2aa4cba6b0a09126a5e7268ec.tar.gz
bcm5719-llvm-2f169e7cdd9973d2aa4cba6b0a09126a5e7268ec.zip
[analyzer] NFC: Introduce sub-classes for path-sensitive and basic reports.
Checkers are now required to specify whether they're creating a path-sensitive report or a path-insensitive report by constructing an object of the respective type. This makes BugReporter more independent from the rest of the Static Analyzer because all Analyzer-specific code is now in sub-classes. Differential Revision: https://reviews.llvm.org/D66572 llvm-svn: 371450
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core')
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporter.cpp260
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp135
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp17
-rw-r--r--clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp5
4 files changed, 233 insertions, 184 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index f5d747c7fdd..331d7379577 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -71,6 +71,7 @@
using namespace clang;
using namespace ento;
+using namespace llvm;
#define DEBUG_TYPE "BugReporter"
@@ -131,7 +132,8 @@ public:
public:
PathDiagnosticConstruct(const PathDiagnosticConsumer *PDC,
- const ExplodedNode *ErrorNode, const BugReport *R);
+ const ExplodedNode *ErrorNode,
+ const PathSensitiveBugReport *R);
/// \returns the location context associated with the current position in the
/// bug path.
@@ -202,7 +204,7 @@ class PathDiagnosticBuilder : public BugReporterContext {
/// them being the last entities being able to modify it (for example,
/// changing interestingness here would cause inconsistencies as to how this
/// file and visitors construct diagnostics), hence its const.
- const BugReport *R;
+ const PathSensitiveBugReport *R;
/// The leaf of the bug path. This isn't the same as the bug reports error
/// node, which refers to the *original* graph, not the bug path.
const ExplodedNode *const ErrorNode;
@@ -215,12 +217,12 @@ public:
/// a PathDiagnosticBuilder able to construct bug reports for different
/// consumers. Returns None if no valid report is found.
static Optional<PathDiagnosticBuilder>
- findValidReport(ArrayRef<BugReport *> &bugReports,
+ findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports,
PathSensitiveBugReporter &Reporter);
PathDiagnosticBuilder(
BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
- BugReport *r, const ExplodedNode *ErrorNode,
+ PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,
std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics);
/// This function is responsible for generating diagnostic pieces that are
@@ -262,7 +264,7 @@ private:
ExecutionContinues(llvm::raw_string_ostream &os,
const PathDiagnosticConstruct &C) const;
- const BugReport *getBugReport() const { return R; }
+ const PathSensitiveBugReport *getBugReport() const { return R; }
};
} // namespace
@@ -369,7 +371,8 @@ static void removeRedundantMsgs(PathPieces &path) {
/// that aren't needed. Return true if afterwards the path contains
/// "interesting stuff" which means it shouldn't be pruned from the parent path.
static bool removeUnneededCalls(const PathDiagnosticConstruct &C,
- PathPieces &pieces, const BugReport *R,
+ PathPieces &pieces,
+ const PathSensitiveBugReport *R,
bool IsInteresting = false) {
bool containsSomethingInteresting = IsInteresting;
const unsigned N = pieces.size();
@@ -1263,13 +1266,23 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
}
static std::unique_ptr<PathDiagnostic>
-generateEmptyDiagnosticForReport(const BugReport *R, const SourceManager &SM) {
+generateDiagnosticForBasicReport(const BasicBugReport *R) {
const BugType &BT = R->getBugType();
return std::make_unique<PathDiagnostic>(
- R->getBugType().getCheckName(), R->getDeclWithIssue(),
- R->getBugType().getName(), R->getDescription(),
- R->getShortDescription(/*UseFallback=*/false), BT.getCategory(),
- R->getUniqueingLocation(), R->getUniqueingDecl(),
+ BT.getCheckName(), R->getDeclWithIssue(), BT.getName(),
+ R->getDescription(), R->getShortDescription(/*UseFallback=*/false),
+ BT.getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
+ std::make_unique<FilesToLineNumsMap>());
+}
+
+static std::unique_ptr<PathDiagnostic>
+generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R,
+ const SourceManager &SM) {
+ const BugType &BT = R->getBugType();
+ return std::make_unique<PathDiagnostic>(
+ BT.getCheckName(), R->getDeclWithIssue(), BT.getName(),
+ R->getDescription(), R->getShortDescription(/*UseFallback=*/false),
+ BT.getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
findExecutedLines(SM, R->getErrorNode()));
}
@@ -1909,7 +1922,7 @@ static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD) {
PathDiagnosticConstruct::PathDiagnosticConstruct(
const PathDiagnosticConsumer *PDC, const ExplodedNode *ErrorNode,
- const BugReport *R)
+ const PathSensitiveBugReport *R)
: Consumer(PDC), CurrentNode(ErrorNode),
SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
PD(generateEmptyDiagnosticForReport(R, getSourceManager())) {
@@ -1918,7 +1931,7 @@ PathDiagnosticConstruct::PathDiagnosticConstruct(
PathDiagnosticBuilder::PathDiagnosticBuilder(
BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
- BugReport *r, const ExplodedNode *ErrorNode,
+ PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,
std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
: BugReporterContext(BRC), BugPath(std::move(BugPath)), R(r),
ErrorNode(ErrorNode),
@@ -1929,7 +1942,6 @@ PathDiagnosticBuilder::generate(const PathDiagnosticConsumer *PDC) const {
PathDiagnosticConstruct Construct(PDC, ErrorNode, R);
const SourceManager &SM = getSourceManager();
- const BugReport *R = getBugReport();
const AnalyzerOptions &Opts = getAnalyzerOptions();
StringRef ErrorTag = ErrorNode->getLocation().getTag()->getTagDescription();
@@ -2050,7 +2062,8 @@ void BuiltinBug::anchor() {}
// Methods for BugReport and subclasses.
//===----------------------------------------------------------------------===//
-void BugReport::addVisitor(std::unique_ptr<BugReporterVisitor> visitor) {
+void PathSensitiveBugReport::addVisitor(
+ std::unique_ptr<BugReporterVisitor> visitor) {
if (!visitor)
return;
@@ -2065,14 +2078,11 @@ void BugReport::addVisitor(std::unique_ptr<BugReporterVisitor> visitor) {
Callbacks.push_back(std::move(visitor));
}
-void BugReport::clearVisitors() {
+void PathSensitiveBugReport::clearVisitors() {
Callbacks.clear();
}
-const Decl *BugReport::getDeclWithIssue() const {
- if (DeclWithIssue)
- return DeclWithIssue;
-
+const Decl *PathSensitiveBugReport::getDeclWithIssue() const {
const ExplodedNode *N = getErrorNode();
if (!N)
return nullptr;
@@ -2081,14 +2091,28 @@ const Decl *BugReport::getDeclWithIssue() const {
return LC->getStackFrame()->getDecl();
}
-void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
+void BasicBugReport::Profile(llvm::FoldingSetNodeID& hash) const {
+ hash.AddInteger(static_cast<int>(getKind()));
+ hash.AddPointer(&BT);
+ hash.AddString(Description);
+ assert(Location.isValid());
+ Location.Profile(hash);
+
+ for (SourceRange range : Ranges) {
+ if (!range.isValid())
+ continue;
+ hash.AddInteger(range.getBegin().getRawEncoding());
+ hash.AddInteger(range.getEnd().getRawEncoding());
+ }
+}
+
+void PathSensitiveBugReport::Profile(llvm::FoldingSetNodeID &hash) const {
+ hash.AddInteger(static_cast<int>(getKind()));
hash.AddPointer(&BT);
hash.AddString(Description);
PathDiagnosticLocation UL = getUniqueingLocation();
if (UL.isValid()) {
UL.Profile(hash);
- } else if (Location.isValid()) {
- Location.Profile(hash);
} else {
assert(ErrorNode);
hash.AddPointer(GetCurrentOrPreviousStmt(ErrorNode));
@@ -2131,8 +2155,8 @@ static void insertToInterestingnessMap(
"have, if it was already marked as interesting with a different kind!");
}
-void BugReport::markInteresting(SymbolRef sym,
- bugreporter::TrackingKind TKind) {
+void PathSensitiveBugReport::markInteresting(SymbolRef sym,
+ bugreporter::TrackingKind TKind) {
if (!sym)
return;
@@ -2142,8 +2166,8 @@ void BugReport::markInteresting(SymbolRef sym,
markInteresting(meta->getRegion(), TKind);
}
-void BugReport::markInteresting(const MemRegion *R,
- bugreporter::TrackingKind TKind) {
+void PathSensitiveBugReport::markInteresting(const MemRegion *R,
+ bugreporter::TrackingKind TKind) {
if (!R)
return;
@@ -2154,19 +2178,20 @@ void BugReport::markInteresting(const MemRegion *R,
markInteresting(SR->getSymbol(), TKind);
}
-void BugReport::markInteresting(SVal V, bugreporter::TrackingKind TKind) {
+void PathSensitiveBugReport::markInteresting(SVal V,
+ bugreporter::TrackingKind TKind) {
markInteresting(V.getAsRegion(), TKind);
markInteresting(V.getAsSymbol(), TKind);
}
-void BugReport::markInteresting(const LocationContext *LC) {
+void PathSensitiveBugReport::markInteresting(const LocationContext *LC) {
if (!LC)
return;
InterestingLocationContexts.insert(LC);
}
Optional<bugreporter::TrackingKind>
-BugReport::getInterestingnessKind(SVal V) const {
+PathSensitiveBugReport::getInterestingnessKind(SVal V) const {
auto RKind = getInterestingnessKind(V.getAsRegion());
auto SKind = getInterestingnessKind(V.getAsSymbol());
if (!RKind)
@@ -2191,7 +2216,7 @@ BugReport::getInterestingnessKind(SVal V) const {
}
Optional<bugreporter::TrackingKind>
-BugReport::getInterestingnessKind(SymbolRef sym) const {
+PathSensitiveBugReport::getInterestingnessKind(SymbolRef sym) const {
if (!sym)
return None;
// We don't currently consider metadata symbols to be interesting
@@ -2203,7 +2228,7 @@ BugReport::getInterestingnessKind(SymbolRef sym) const {
}
Optional<bugreporter::TrackingKind>
-BugReport::getInterestingnessKind(const MemRegion *R) const {
+PathSensitiveBugReport::getInterestingnessKind(const MemRegion *R) const {
if (!R)
return None;
@@ -2217,25 +2242,25 @@ BugReport::getInterestingnessKind(const MemRegion *R) const {
return None;
}
-bool BugReport::isInteresting(SVal V) const {
+bool PathSensitiveBugReport::isInteresting(SVal V) const {
return getInterestingnessKind(V).hasValue();
}
-bool BugReport::isInteresting(SymbolRef sym) const {
+bool PathSensitiveBugReport::isInteresting(SymbolRef sym) const {
return getInterestingnessKind(sym).hasValue();
}
-bool BugReport::isInteresting(const MemRegion *R) const {
+bool PathSensitiveBugReport::isInteresting(const MemRegion *R) const {
return getInterestingnessKind(R).hasValue();
}
-bool BugReport::isInteresting(const LocationContext *LC) const {
+bool PathSensitiveBugReport::isInteresting(const LocationContext *LC) const {
if (!LC)
return false;
return InterestingLocationContexts.count(LC);
}
-const Stmt *BugReport::getStmt() const {
+const Stmt *PathSensitiveBugReport::getStmt() const {
if (!ErrorNode)
return nullptr;
@@ -2253,31 +2278,19 @@ const Stmt *BugReport::getStmt() const {
return S;
}
-llvm::iterator_range<BugReport::ranges_iterator> BugReport::getRanges() const {
+ArrayRef<SourceRange>
+PathSensitiveBugReport::getRanges() const {
// If no custom ranges, add the range of the statement corresponding to
// the error node.
- if (Ranges.empty()) {
- if (dyn_cast_or_null<Expr>(getStmt()))
- return llvm::make_range(&ErrorNodeRange, &ErrorNodeRange + 1);
- return llvm::make_range(ranges_iterator(), ranges_iterator());
- }
+ if (Ranges.empty() && isa_and_nonnull<Expr>(getStmt()))
+ return ErrorNodeRange;
- // User-specified absence of range info.
- if (Ranges.size() == 1 && !Ranges.begin()->isValid())
- return llvm::make_range(ranges_iterator(), ranges_iterator());
-
- return llvm::make_range(Ranges.begin(), Ranges.end());
+ return Ranges;
}
-PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const {
- if (ErrorNode) {
- assert(!Location.isValid() &&
- "Either Location or ErrorNode should be specified but not both.");
- return PathDiagnosticLocation::createEndOfPath(ErrorNode, SM);
- }
-
- assert(Location.isValid());
- return Location;
+PathDiagnosticLocation
+PathSensitiveBugReport::getLocation() const {
+ return PathDiagnosticLocation::createEndOfPath(ErrorNode);
}
//===----------------------------------------------------------------------===//
@@ -2326,7 +2339,7 @@ namespace {
class BugPathInfo {
public:
std::unique_ptr<ExplodedGraph> BugPath;
- BugReport *Report;
+ PathSensitiveBugReport *Report;
const ExplodedNode *ErrorNode;
};
@@ -2342,7 +2355,8 @@ class BugPathGetter {
/// Since the getErrorNode() or BugReport refers to the original ExplodedGraph,
/// we need to pair it to the error node of the constructed trimmed graph.
- using ReportNewNodePair = std::pair<BugReport *, const ExplodedNode *>;
+ using ReportNewNodePair =
+ std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
SmallVector<ReportNewNodePair, 32> ReportNodes;
BugPathInfo CurrentBugPath;
@@ -2377,7 +2391,7 @@ class BugPathGetter {
public:
BugPathGetter(const ExplodedGraph *OriginalGraph,
- ArrayRef<BugReport *> &bugReports);
+ ArrayRef<PathSensitiveBugReport *> &bugReports);
BugPathInfo *getNextBugPath();
};
@@ -2385,7 +2399,7 @@ public:
} // namespace
BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph,
- ArrayRef<BugReport *> &bugReports) {
+ ArrayRef<PathSensitiveBugReport *> &bugReports) {
SmallVector<const ExplodedNode *, 32> Nodes;
for (const auto I : bugReports) {
assert(I->isValid() &&
@@ -2404,7 +2418,7 @@ BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph,
// in the new graph.
llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
- for (BugReport *Report : bugReports) {
+ for (PathSensitiveBugReport *Report : bugReports) {
const ExplodedNode *NewNode = ForwardMap.lookup(Report->getErrorNode());
assert(NewNode &&
"Failed to construct a trimmed graph that contains this error "
@@ -2592,11 +2606,12 @@ static void CompactMacroExpandedPieces(PathPieces &path,
/// Notes associated with {@code ErrorNode} are generated using
/// {@code getEndPath}, and the rest are generated with {@code VisitNode}.
static std::unique_ptr<VisitorsDiagnosticsTy>
-generateVisitorsDiagnostics(BugReport *R, const ExplodedNode *ErrorNode,
+generateVisitorsDiagnostics(PathSensitiveBugReport *R,
+ const ExplodedNode *ErrorNode,
BugReporterContext &BRC) {
std::unique_ptr<VisitorsDiagnosticsTy> Notes =
std::make_unique<VisitorsDiagnosticsTy>();
- BugReport::VisitorList visitors;
+ PathSensitiveBugReport::VisitorList visitors;
// Run visitors on all nodes starting from the node *before* the last one.
// The last node is reserved for notes generated with {@code getEndPath}.
@@ -2646,15 +2661,15 @@ generateVisitorsDiagnostics(BugReport *R, const ExplodedNode *ErrorNode,
return Notes;
}
-Optional<PathDiagnosticBuilder>
-PathDiagnosticBuilder::findValidReport(ArrayRef<BugReport *> &bugReports,
- PathSensitiveBugReporter &Reporter) {
+Optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
+ ArrayRef<PathSensitiveBugReport *> &bugReports,
+ PathSensitiveBugReporter &Reporter) {
BugPathGetter BugGraph(&Reporter.getGraph(), bugReports);
while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
// Find the BugReport with the original location.
- BugReport *R = BugPath->Report;
+ PathSensitiveBugReport *R = BugPath->Report;
assert(R && "No original report found for sliced graph.");
assert(R->isValid() && "Report selected by trimmed graph marked invalid.");
const ExplodedNode *ErrorNode = BugPath->ErrorNode;
@@ -2700,7 +2715,7 @@ PathDiagnosticBuilder::findValidReport(ArrayRef<BugReport *> &bugReports,
std::unique_ptr<DiagnosticForConsumerMapTy>
PathSensitiveBugReporter::generatePathDiagnostics(
ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> &bugReports) {
+ ArrayRef<PathSensitiveBugReport *> &bugReports) {
assert(!bugReports.empty());
auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
@@ -2720,24 +2735,7 @@ PathSensitiveBugReporter::generatePathDiagnostics(
}
void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
- if (const ExplodedNode *E = R->getErrorNode()) {
- // An error node must either be a sink or have a tag, otherwise
- // it could get reclaimed before the path diagnostic is created.
- assert((E->isSink() || E->getLocation().getTag()) &&
- "Error node must either be a sink or have a tag");
-
- const AnalysisDeclContext *DeclCtx =
- E->getLocationContext()->getAnalysisDeclContext();
- // The source of autosynthesized body can be handcrafted AST or a model
- // file. The locations from handcrafted ASTs have no valid source locations
- // and have to be discarded. Locations from model files should be preserved
- // for processing and reporting.
- if (DeclCtx->isBodyAutosynthesized() &&
- !DeclCtx->isBodyAutosynthesizedFromModelFile())
- return;
- }
-
- bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid();
+ bool ValidSourceLoc = R->getLocation().isValid();
assert(ValidSourceLoc);
// If we mess up in a release build, we'd still prefer to just drop the bug
// instead of trying to go on.
@@ -2760,6 +2758,28 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
EQ->AddReport(std::move(R));
}
+void PathSensitiveBugReporter::emitReport(std::unique_ptr<BugReport> R) {
+ if (auto PR = dyn_cast<PathSensitiveBugReport>(R.get()))
+ if (const ExplodedNode *E = PR->getErrorNode()) {
+ // An error node must either be a sink or have a tag, otherwise
+ // it could get reclaimed before the path diagnostic is created.
+ assert((E->isSink() || E->getLocation().getTag()) &&
+ "Error node must either be a sink or have a tag");
+
+ const AnalysisDeclContext *DeclCtx =
+ E->getLocationContext()->getAnalysisDeclContext();
+ // The source of autosynthesized body can be handcrafted AST or a model
+ // file. The locations from handcrafted ASTs have no valid source
+ // locations and have to be discarded. Locations from model files should
+ // be preserved for processing and reporting.
+ if (DeclCtx->isBodyAutosynthesized() &&
+ !DeclCtx->isBodyAutosynthesizedFromModelFile())
+ return;
+ }
+
+ BugReporter::emitReport(std::move(R));
+}
+
//===----------------------------------------------------------------------===//
// Emitting reports in equivalence classes.
//===----------------------------------------------------------------------===//
@@ -2776,9 +2796,8 @@ struct FRIEC_WLItem {
} // namespace
-static BugReport *
-FindReportInEquivalenceClass(BugReportEquivClass& EQ,
- SmallVectorImpl<BugReport*> &bugReports) {
+BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
+ BugReportEquivClass &EQ, SmallVectorImpl<BugReport *> &bugReports) {
BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
assert(I != E);
const BugType& BT = I->getBugType();
@@ -2789,10 +2808,9 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
if (!BT.isSuppressOnSink()) {
BugReport *R = &*I;
for (auto &I : EQ) {
- const ExplodedNode *N = I.getErrorNode();
- if (N) {
- R = &I;
- bugReports.push_back(R);
+ if (auto *PR = dyn_cast<PathSensitiveBugReport>(&I)) {
+ R = PR;
+ bugReports.push_back(PR);
}
}
return R;
@@ -2807,19 +2825,20 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
BugReport *exampleReport = nullptr;
for (; I != E; ++I) {
- const ExplodedNode *errorNode = I->getErrorNode();
-
- if (!errorNode)
+ auto *R = dyn_cast<PathSensitiveBugReport>(&*I);
+ if (!R)
continue;
+
+ const ExplodedNode *errorNode = R->getErrorNode();
if (errorNode->isSink()) {
llvm_unreachable(
"BugType::isSuppressSink() should not be 'true' for sink end nodes");
}
// No successors? By definition this nodes isn't post-dominated by a sink.
if (errorNode->succ_empty()) {
- bugReports.push_back(&*I);
+ bugReports.push_back(R);
if (!exampleReport)
- exampleReport = &*I;
+ exampleReport = R;
continue;
}
@@ -2852,9 +2871,9 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
if (Succ->succ_empty()) {
// If we found an end-of-path node that is not a sink.
if (!Succ->isSink()) {
- bugReports.push_back(&*I);
+ bugReports.push_back(R);
if (!exampleReport)
- exampleReport = &*I;
+ exampleReport = R;
WL.clear();
break;
}
@@ -2885,7 +2904,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
void BugReporter::FlushReport(BugReportEquivClass& EQ) {
SmallVector<BugReport*, 10> bugReports;
- BugReport *report = FindReportInEquivalenceClass(EQ, bugReports);
+ BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
if (!report)
return;
@@ -2900,7 +2919,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
// If the path is empty, generate a single step path with the location
// of the issue.
if (PD->path.empty()) {
- PathDiagnosticLocation L = report->getLocation(getSourceManager());
+ PathDiagnosticLocation L = report->getLocation();
auto piece = std::make_unique<PathDiagnosticEventPiece>(
L, report->getDescription());
for (SourceRange Range : report->getRanges())
@@ -3015,16 +3034,24 @@ findExecutedLines(const SourceManager &SM, const ExplodedNode *N) {
std::unique_ptr<DiagnosticForConsumerMapTy>
BugReporter::generateDiagnosticForConsumerMap(
- BugReport *report, ArrayRef<PathDiagnosticConsumer *> consumers,
+ BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
ArrayRef<BugReport *> bugReports) {
+ auto *basicReport = cast<BasicBugReport>(exampleReport);
+ auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
+ for (auto *Consumer : consumers)
+ (*Out)[Consumer] = generateDiagnosticForBasicReport(basicReport);
+ return Out;
+}
- if (!report->isPathSensitive()) {
- auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
- for (auto *Consumer : consumers)
- (*Out)[Consumer] = generateEmptyDiagnosticForReport(report,
- getSourceManager());
- return Out;
- }
+std::unique_ptr<DiagnosticForConsumerMapTy>
+PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
+ BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> bugReports) {
+ std::vector<BasicBugReport *> BasicBugReports;
+ std::vector<PathSensitiveBugReport *> PathSensitiveBugReports;
+ if (isa<BasicBugReport>(exampleReport))
+ return BugReporter::generateDiagnosticForConsumerMap(exampleReport,
+ consumers, bugReports);
// Generate the full path sensitive diagnostic, using the generation scheme
// specified by the PathDiagnosticConsumer. Note that we have to generate
@@ -3032,8 +3059,13 @@ BugReporter::generateDiagnosticForConsumerMap(
// the BugReporterVisitors may mark this bug as a false positive.
assert(!bugReports.empty());
MaxBugClassSize.updateMax(bugReports.size());
- std::unique_ptr<DiagnosticForConsumerMapTy> Out =
- generatePathDiagnostics(consumers, bugReports);
+
+ // Avoid copying the whole array because there may be a lot of reports.
+ ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports(
+ reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.begin()),
+ reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.end()));
+ std::unique_ptr<DiagnosticForConsumerMapTy> Out = generatePathDiagnostics(
+ consumers, convertedArrayOfReports);
if (Out->empty())
return Out;
@@ -3068,7 +3100,7 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
ArrayRef<FixItHint> Fixits) {
// 'BT' is owned by BugReporter.
BugType *BT = getBugTypeForName(CheckName, name, category);
- auto R = std::make_unique<BugReport>(*BT, str, Loc);
+ auto R = std::make_unique<BasicBugReport>(*BT, str, Loc);
R->setDeclWithIssue(DeclWithIssue);
for (const auto &SR : Ranges)
R->addRange(SR);
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index b223c6fb496..7b26b8fabb9 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -215,7 +215,7 @@ getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) {
static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
const ExplodedNode *N,
- const BugReport *B) {
+ const PathSensitiveBugReport *B) {
// Even if this condition is marked as interesting, it isn't *that*
// interesting if it didn't happen in a nested stackframe, the user could just
// follow the arrows.
@@ -230,7 +230,7 @@ static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
}
static bool isInterestingExpr(const Expr *E, const ExplodedNode *N,
- const BugReport *B) {
+ const PathSensitiveBugReport *B) {
if (Optional<SVal> V = getSValForVar(E, N))
return B->getInterestingnessKind(*V).hasValue();
return false;
@@ -296,19 +296,20 @@ static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest,
PathDiagnosticPieceRef BugReporterVisitor::getEndPath(BugReporterContext &,
const ExplodedNode *,
- BugReport &) {
+ PathSensitiveBugReport &) {
return nullptr;
}
void BugReporterVisitor::finalizeVisitor(BugReporterContext &,
- const ExplodedNode *, BugReport &) {}
+ const ExplodedNode *,
+ PathSensitiveBugReport &) {}
PathDiagnosticPieceRef
BugReporterVisitor::getDefaultEndPath(const BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
- const BugReport &BR) {
- PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(
- EndPathNode, BRC.getSourceManager());
+ const PathSensitiveBugReport &BR) {
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::createEndOfPath(EndPathNode);
const auto &Ranges = BR.getRanges();
@@ -376,7 +377,7 @@ public:
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BR,
- BugReport &R) override;
+ PathSensitiveBugReport &R) override;
private:
/// Attempts to find the region of interest in a given record decl,
@@ -410,10 +411,10 @@ private:
/// \return Diagnostics piece for region not modified in the current function,
/// if it decides to emit one.
PathDiagnosticPieceRef
- maybeEmitNote(BugReport &R, const CallEvent &Call, const ExplodedNode *N,
- const RegionVector &FieldChain, const MemRegion *MatchedRegion,
- StringRef FirstElement, bool FirstIsReferenceType,
- unsigned IndirectionLevel);
+ maybeEmitNote(PathSensitiveBugReport &R, const CallEvent &Call,
+ const ExplodedNode *N, const RegionVector &FieldChain,
+ const MemRegion *MatchedRegion, StringRef FirstElement,
+ bool FirstIsReferenceType, unsigned IndirectionLevel);
/// Pretty-print region \p MatchedRegion to \p os.
/// \return Whether printing succeeded.
@@ -542,9 +543,9 @@ NoStoreFuncVisitor::findRegionOfInterestInRecord(
return None;
}
-PathDiagnosticPieceRef NoStoreFuncVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BR,
- BugReport &R) {
+PathDiagnosticPieceRef
+NoStoreFuncVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BR,
+ PathSensitiveBugReport &R) {
const LocationContext *Ctx = N->getLocationContext();
const StackFrameContext *SCtx = Ctx->getStackFrame();
@@ -656,7 +657,7 @@ static llvm::StringLiteral WillBeUsedForACondition =
", which participates in a condition later";
PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote(
- BugReport &R, const CallEvent &Call, const ExplodedNode *N,
+ PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N,
const RegionVector &FieldChain, const MemRegion *MatchedRegion,
StringRef FirstElement, bool FirstIsReferenceType,
unsigned IndirectionLevel) {
@@ -803,7 +804,7 @@ public:
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
- BugReport &BR) override {
+ PathSensitiveBugReport &BR) override {
if (WasModified)
return nullptr;
@@ -829,7 +830,7 @@ public:
static void addMacroVisitorIfNecessary(
const ExplodedNode *N, const MemRegion *R,
- bool EnableNullFPSuppression, BugReport &BR,
+ bool EnableNullFPSuppression, PathSensitiveBugReport &BR,
const SVal V) {
AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
if (EnableNullFPSuppression &&
@@ -923,7 +924,7 @@ public:
/// the statement is a call that was inlined, we add the visitor to the
/// bug report, so it can print a note later.
static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S,
- BugReport &BR,
+ PathSensitiveBugReport &BR,
bool InEnableNullFPSuppression,
bugreporter::TrackingKind TKind) {
if (!CallEvent::isCallStmt(S))
@@ -1003,7 +1004,7 @@ public:
PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N,
BugReporterContext &BRC,
- BugReport &BR) {
+ PathSensitiveBugReport &BR) {
// Only print a message at the interesting return statement.
if (N->getLocationContext() != CalleeSFC)
return nullptr;
@@ -1130,10 +1131,8 @@ public:
PathDiagnosticPieceRef visitNodeMaybeUnsuppress(const ExplodedNode *N,
BugReporterContext &BRC,
- BugReport &BR) {
-#ifndef NDEBUG
+ PathSensitiveBugReport &BR) {
assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
-#endif
// Are we at the entry node for this call?
Optional<CallEnter> CE = N->getLocationAs<CallEnter>();
@@ -1179,7 +1178,7 @@ public:
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
- BugReport &BR) override {
+ PathSensitiveBugReport &BR) override {
switch (Mode) {
case Initial:
return visitNodeInitial(N, BRC, BR);
@@ -1193,7 +1192,7 @@ public:
}
void finalizeVisitor(BugReporterContext &, const ExplodedNode *,
- BugReport &BR) override {
+ PathSensitiveBugReport &BR) override {
if (EnableNullFPSuppression && ShouldInvalidate)
BR.markInvalid(ReturnVisitor::getTag(), CalleeSFC);
}
@@ -1316,9 +1315,8 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream& os,
}
/// Show default diagnostics for storing bad region.
-static void showBRDefaultDiagnostics(llvm::raw_svector_ostream& os,
- const MemRegion *R,
- SVal V) {
+static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &os,
+ const MemRegion *R, SVal V) {
if (V.getAs<loc::ConcreteInt>()) {
bool b = false;
if (R->isBoundable()) {
@@ -1363,7 +1361,8 @@ static void showBRDefaultDiagnostics(llvm::raw_svector_ostream& os,
PathDiagnosticPieceRef
FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC, BugReport &BR) {
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
if (Satisfied)
return nullptr;
@@ -1540,9 +1539,8 @@ bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
return (bool)N->getState()->assume(Constraint, !Assumption);
}
-PathDiagnosticPieceRef
-TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &) {
+PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {
const ExplodedNode *PrevN = N->getFirstPred();
if (IsSatisfied)
return nullptr;
@@ -1620,8 +1618,10 @@ const char *SuppressInlineDefensiveChecksVisitor::getTag() {
return "IDCVisitor";
}
-PathDiagnosticPieceRef SuppressInlineDefensiveChecksVisitor::VisitNode(
- const ExplodedNode *Succ, BugReporterContext &BRC, BugReport &BR) {
+PathDiagnosticPieceRef
+SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
const ExplodedNode *Pred = Succ->getFirstPred();
if (IsSatisfied)
return nullptr;
@@ -1722,7 +1722,7 @@ public:
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
- BugReport &BR) override;
+ PathSensitiveBugReport &BR) override;
};
} // end of anonymous namespace
@@ -1778,8 +1778,10 @@ static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context) {
return false;
}
-PathDiagnosticPieceRef TrackControlDependencyCondBRVisitor::VisitNode(
- const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) {
+PathDiagnosticPieceRef
+TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
// We can only reason about control dependencies within the same stack frame.
if (Origin->getStackFrame() != N->getStackFrame())
return nullptr;
@@ -1925,7 +1927,8 @@ static const ExplodedNode* findNodeForExpression(const ExplodedNode *N,
}
bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
- const Expr *E, BugReport &report,
+ const Expr *E,
+ PathSensitiveBugReport &report,
bugreporter::TrackingKind TKind,
bool EnableNullFPSuppression) {
@@ -2082,9 +2085,9 @@ const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
return nullptr;
}
-PathDiagnosticPieceRef NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) {
+PathDiagnosticPieceRef
+NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
Optional<PreStmt> P = N->getLocationAs<PreStmt>();
if (!P)
return nullptr;
@@ -2127,9 +2130,9 @@ PathDiagnosticPieceRef NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
/// to make all PathDiagnosticPieces created by this visitor.
const char *ConditionBRVisitor::getTag() { return "ConditionBRVisitor"; }
-PathDiagnosticPieceRef ConditionBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) {
+PathDiagnosticPieceRef
+ConditionBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
auto piece = VisitNodeImpl(N, BRC, BR);
if (piece) {
piece->setTag(getTag());
@@ -2141,7 +2144,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitNode(const ExplodedNode *N,
PathDiagnosticPieceRef
ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
ProgramPoint ProgPoint = N->getLocation();
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
ExprEngine::geteagerlyAssumeBinOpBifurcationTags();
@@ -2179,7 +2183,8 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
PathDiagnosticPieceRef ConditionBRVisitor::VisitTerminator(
const Stmt *Term, const ExplodedNode *N, const CFGBlock *srcBlk,
- const CFGBlock *dstBlk, BugReport &R, BugReporterContext &BRC) {
+ const CFGBlock *dstBlk, PathSensitiveBugReport &R,
+ BugReporterContext &BRC) {
const Expr *Cond = nullptr;
// In the code below, Term is a CFG terminator and Cond is a branch condition
@@ -2236,8 +2241,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTerminator(
PathDiagnosticPieceRef
ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
- BugReport &R, const ExplodedNode *N,
- bool TookTrue) {
+ PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue) {
ProgramStateRef CurrentState = N->getState();
ProgramStateRef PrevState = N->getFirstPred()->getState();
const LocationContext *LCtx = N->getLocationContext();
@@ -2307,7 +2312,7 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex,
const Expr *ParentEx,
raw_ostream &Out,
BugReporterContext &BRC,
- BugReport &report,
+ PathSensitiveBugReport &report,
const ExplodedNode *N,
Optional<bool> &prunable,
bool IsSameFieldName) {
@@ -2392,7 +2397,8 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex,
PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
const Expr *Cond, const BinaryOperator *BExpr, BugReporterContext &BRC,
- BugReport &R, const ExplodedNode *N, bool TookTrue, bool IsAssuming) {
+ PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming) {
bool shouldInvert = false;
Optional<bool> shouldPrune;
@@ -2511,7 +2517,7 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable(
StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC,
- BugReport &report, const ExplodedNode *N, bool TookTrue) {
+ PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue) {
// FIXME: If there's already a constraint tracker for this variable,
// we shouldn't emit anything here (c.f. the double note in
// test/Analysis/inlining/path-notes.c)
@@ -2538,7 +2544,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable(
PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
const Expr *Cond, const DeclRefExpr *DRE, BugReporterContext &BRC,
- BugReport &report, const ExplodedNode *N, bool TookTrue, bool IsAssuming) {
+ PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming) {
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
if (!VD)
return nullptr;
@@ -2573,7 +2580,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
const Expr *Cond, const MemberExpr *ME, BugReporterContext &BRC,
- BugReport &report, const ExplodedNode *N, bool TookTrue, bool IsAssuming) {
+ PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming) {
SmallString<256> Buf;
llvm::raw_svector_ostream Out(Buf);
@@ -2659,7 +2667,8 @@ bool ConditionBRVisitor::isPieceMessageGeneric(
//===----------------------------------------------------------------------===//
void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
- BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR) {
+ BugReporterContext &BRC, const ExplodedNode *N,
+ PathSensitiveBugReport &BR) {
// Here we suppress false positives coming from system headers. This list is
// based on known issues.
const AnalyzerOptions &Options = BRC.getAnalyzerOptions();
@@ -2730,7 +2739,7 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
// Skip reports within the sys/queue.h macros as we do not have the ability to
// reason about data structure shapes.
const SourceManager &SM = BRC.getSourceManager();
- FullSourceLoc Loc = BR.getLocation(SM).asLocation();
+ FullSourceLoc Loc = BR.getLocation().asLocation();
while (Loc.isMacroID()) {
Loc = Loc.getSpellingLoc();
if (SM.getFilename(Loc).endswith("sys/queue.h")) {
@@ -2744,9 +2753,9 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
// Implementation of UndefOrNullArgVisitor.
//===----------------------------------------------------------------------===//
-PathDiagnosticPieceRef UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) {
+PathDiagnosticPieceRef
+UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
ProgramStateRef State = N->getState();
ProgramPoint ProgLoc = N->getLocation();
@@ -2802,7 +2811,8 @@ FalsePositiveRefutationBRVisitor::FalsePositiveRefutationBRVisitor()
: Constraints(ConstraintRangeTy::Factory().getEmptyMap()) {}
void FalsePositiveRefutationBRVisitor::finalizeVisitor(
- BugReporterContext &BRC, const ExplodedNode *EndPathNode, BugReport &BR) {
+ BugReporterContext &BRC, const ExplodedNode *EndPathNode,
+ PathSensitiveBugReport &BR) {
// Collect new constraints
VisitNode(EndPathNode, BRC, BR);
@@ -2837,9 +2847,8 @@ void FalsePositiveRefutationBRVisitor::finalizeVisitor(
BR.markInvalid("Infeasible constraints", EndPathNode->getLocationContext());
}
-PathDiagnosticPieceRef
-FalsePositiveRefutationBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &, BugReport &) {
+PathDiagnosticPieceRef FalsePositiveRefutationBRVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &, PathSensitiveBugReport &) {
// Collect new constraints
const ConstraintRangeTy &NewCs = N->getState()->get<ConstraintRange>();
ConstraintRangeTy::Factory &CF =
@@ -2875,7 +2884,7 @@ void TagVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
PathDiagnosticPieceRef TagVisitor::VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
- BugReport &R) {
+ PathSensitiveBugReport &R) {
ProgramPoint PP = N->getLocation();
const NoteTag *T = dyn_cast_or_null<NoteTag>(PP.getTag());
if (!T)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index c5a1f9b857e..de23a3ca75f 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3004,9 +3004,13 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
llvm::make_range(BR.EQClasses_begin(), BR.EQClasses_end());
for (const auto &EQ : EQClasses) {
- for (const BugReport &Report : EQ) {
- if (Report.getErrorNode()->getState() == N->getState() &&
- Report.getErrorNode()->getLocation() == N->getLocation())
+ for (const BugReport &R : EQ) {
+ const auto *PR = dyn_cast<PathSensitiveBugReport>(&R);
+ if (!PR)
+ continue;
+ const ExplodedNode *EN = PR->getErrorNode();
+ if (EN->getState() == N->getState() &&
+ EN->getLocation() == N->getLocation())
return true;
}
}
@@ -3131,8 +3135,11 @@ std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) {
// Iterate through the reports and get their nodes.
for (BugReporter::EQClasses_iterator
EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) {
- const auto *N = const_cast<ExplodedNode *>(EI->begin()->getErrorNode());
- if (N) Src.push_back(N);
+ const auto *R = dyn_cast<PathSensitiveBugReport>(&*EI->begin());
+ if (!R)
+ continue;
+ const auto *N = const_cast<ExplodedNode *>(R->getErrorNode());
+ Src.push_back(N);
}
return DumpGraph(Src, Filename);
} else {
diff --git a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 2d3b50082c7..f049a1c4120 100644
--- a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -850,11 +850,12 @@ const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
}
PathDiagnosticLocation
- PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
- const SourceManager &SM) {
+PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N) {
assert(N && "Cannot create a location with a null node.");
const Stmt *S = getStmt(N);
const LocationContext *LC = N->getLocationContext();
+ SourceManager &SM =
+ N->getState()->getStateManager().getContext().getSourceManager();
if (!S) {
// If this is an implicit call, return the implicit call point location.
OpenPOWER on IntegriCloud