diff options
author | Ted Kremenek <kremenek@apple.com> | 2012-02-28 23:06:21 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2012-02-28 23:06:21 +0000 |
commit | c89f4b05721f53cfbaf32fc0c4919a4616e68440 (patch) | |
tree | 5c1742cecf2a398a94d5bdce4fc8b037bfac9585 | |
parent | 15f87771cae0c31da45c05b34841d0a2ca70bc87 (diff) |
[analyzer diagnostics] start prototyping stripping PathDiagnostics of unnecessary cruft caused by path inlining.
This introduces a concept of a "prunable" PathDiagnosticEvent. Currently this is a flag, but
we may evolve the concept to make this more dynamically inferred.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151663 91177308-0d34-0410-b5e6-96231b3b80d8
4 files changed, 74 insertions, 3 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h index 466849be03..5434257dd4 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -132,11 +132,17 @@ public: ID.AddPointer(&x); } + virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, const ExplodedNode *Prev, BugReporterContext &BRC, BugReport &BR); + PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR); + PathDiagnosticPiece *VisitTerminator(const Stmt *Term, const ExplodedNode *N, const CFGBlock *srcBlk, diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 1c95497e1c..42d8482eba 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -353,14 +353,18 @@ public: }; class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { - + bool IsPrunable; public: PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, StringRef s, bool addPosRange = true) - : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange), + IsPrunable(false) {} ~PathDiagnosticEventPiece(); + void setPrunable(bool isPrunable) { IsPrunable = isPrunable; } + bool isPrunable() const { return IsPrunable; } + static inline bool classof(const PathDiagnosticPiece *P) { return P->getKind() == Event; } @@ -527,7 +531,7 @@ public: void pushActivePath(PathPieces *p) { pathStack.push_back(p); } void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } - + PathDiagnostic(); PathDiagnostic(StringRef bugtype, StringRef desc, StringRef category); diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index de3c8ed81a..8d9b614841 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -111,6 +111,51 @@ GetCurrentOrNextStmt(const ExplodedNode *N) { } //===----------------------------------------------------------------------===// +// Diagnostic cleanup. +//===----------------------------------------------------------------------===// + +/// Recursively scan through a path and prune out calls and macros pieces +/// that aren't needed. Return true if afterwards the path contains +/// "interesting stuff" which means it should be pruned from the parent path. +static bool RemoveUneededCalls(PathPieces &pieces) { + bool containsSomethingInteresting = false; + const unsigned N = pieces.size(); + + for (unsigned i = 0 ; i < N ; ++i) { + // Remove the front piece from the path. If it is still something we + // want to keep once we are done, we will push it back on the end. + IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front()); + pieces.pop_front(); + + if (PathDiagnosticCallPiece *call = + dyn_cast<PathDiagnosticCallPiece>(piece)) { + // Recursively clean out the subclass. Keep this call around if + // it contains any informative diagnostics. + if (!RemoveUneededCalls(call->path)) + continue; + containsSomethingInteresting = true; + } + else if (PathDiagnosticMacroPiece *macro = + dyn_cast<PathDiagnosticMacroPiece>(piece)) { + if (!RemoveUneededCalls(macro->subPieces)) + continue; + containsSomethingInteresting = true; + } + else if (PathDiagnosticEventPiece *event = + dyn_cast<PathDiagnosticEventPiece>(piece)) { + // We never throw away an event, but we do throw it away wholesale + // as part of a path if we throw the entire path away. + if (!event->isPrunable()) + containsSomethingInteresting = true; + } + + pieces.push_back(piece); + } + + return containsSomethingInteresting; +} + +//===----------------------------------------------------------------------===// // PathDiagnosticBuilder and its associated routines and helper objects. //===----------------------------------------------------------------------===// @@ -1749,6 +1794,11 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, GenerateMinimalPathDiagnostic(PD, PDB, N); break; } + + // Finally, prune the diagnostic path of uninteresting stuff. + bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces()); + assert(hasSomethingInteresting); + (void) hasSomethingInteresting; } void BugReporter::Register(BugType *BT) { diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 2980190945..1d29d5ff0a 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -436,6 +436,17 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *Prev, BugReporterContext &BRC, BugReport &BR) { + PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR); + if (PathDiagnosticEventPiece *ev = + dyn_cast_or_null<PathDiagnosticEventPiece>(piece)) + ev->setPrunable(true); + return piece; +} + +PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR) { const ProgramPoint &progPoint = N->getLocation(); |