[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:
parent
265a421dd9
commit
2429c6ffe7
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue