[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.

llvm-svn: 151663
This commit is contained in:
Ted Kremenek 2012-02-28 23:06:21 +00:00
parent 265a421dd9
commit 2429c6ffe7
4 changed files with 74 additions and 3 deletions

View File

@ -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,

View File

@ -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);

View File

@ -110,6 +110,51 @@ GetCurrentOrNextStmt(const ExplodedNode *N) {
return GetNextStmt(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) {

View File

@ -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();