Rewrite control-flow diagnostic generation "extensive" algorithm using "edge
contexts". This allows us to use a stack of contexts to keep track of what control-flow pieces to include when exiting blocks like 'if', 'for', etc. llvm-svn: 68473
This commit is contained in:
parent
2ed6a20934
commit
c4c9ed0f9b
|
|
@ -456,6 +456,8 @@ public:
|
||||||
// "Minimal" path diagnostic generation algorithm.
|
// "Minimal" path diagnostic generation algorithm.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM);
|
||||||
|
|
||||||
static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
|
static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
|
||||||
PathDiagnosticBuilder &PDB,
|
PathDiagnosticBuilder &PDB,
|
||||||
const ExplodedNode<GRState> *N) {
|
const ExplodedNode<GRState> *N) {
|
||||||
|
|
@ -740,6 +742,10 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
|
||||||
PDB.getStateManager().iterBindings(N->getState(), SNS);
|
PDB.getStateManager().iterBindings(N->getState(), SNS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After constructing the full PathDiagnostic, do a pass over it to compact
|
||||||
|
// PathDiagnosticPieces that occur within a macro.
|
||||||
|
CompactPathDiagnostic(PD, PDB.getSourceManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
@ -764,6 +770,258 @@ static bool IsControlFlowExpr(const Stmt *S) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class VISIBILITY_HIDDEN EdgeBuilder {
|
||||||
|
std::vector<PathDiagnosticLocation> CLocs;
|
||||||
|
typedef std::vector<PathDiagnosticLocation>::iterator iterator;
|
||||||
|
PathDiagnostic &PD;
|
||||||
|
PathDiagnosticBuilder &PDB;
|
||||||
|
PathDiagnosticLocation PrevLoc;
|
||||||
|
|
||||||
|
bool containsLocation(const PathDiagnosticLocation &Container,
|
||||||
|
const PathDiagnosticLocation &Containee);
|
||||||
|
|
||||||
|
PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L);
|
||||||
|
void rawAddEdge(PathDiagnosticLocation NewLoc);
|
||||||
|
|
||||||
|
void popLocation() {
|
||||||
|
rawAddEdge(CLocs.back());
|
||||||
|
CLocs.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
PathDiagnosticLocation IgnoreParens(const PathDiagnosticLocation &L);
|
||||||
|
|
||||||
|
public:
|
||||||
|
EdgeBuilder(PathDiagnostic &pd, PathDiagnosticBuilder &pdb)
|
||||||
|
: PD(pd), PDB(pdb) {
|
||||||
|
CLocs.push_back(PathDiagnosticLocation(&PDB.getCodeDecl(),
|
||||||
|
PDB.getSourceManager()));
|
||||||
|
if (!PD.empty()) {
|
||||||
|
PrevLoc = PD.begin()->getLocation();
|
||||||
|
|
||||||
|
if (const Stmt *S = PrevLoc.asStmt())
|
||||||
|
addContext(PDB.getEnclosingStmtLocation(S).asStmt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~EdgeBuilder() {
|
||||||
|
while (!CLocs.empty()) popLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false);
|
||||||
|
|
||||||
|
void addEdge(const Stmt *S, bool alwaysAdd = false) {
|
||||||
|
addEdge(PathDiagnosticLocation(S, PDB.getSourceManager()), alwaysAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addContext(const Stmt *S);
|
||||||
|
};
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
PathDiagnosticLocation
|
||||||
|
EdgeBuilder::getContextLocation(const PathDiagnosticLocation &L) {
|
||||||
|
if (const Stmt *S = L.asStmt()) {
|
||||||
|
if (IsControlFlowExpr(S))
|
||||||
|
return L;
|
||||||
|
|
||||||
|
return PDB.getEnclosingStmtLocation(S);
|
||||||
|
}
|
||||||
|
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
|
||||||
|
const PathDiagnosticLocation &Containee) {
|
||||||
|
|
||||||
|
if (Container == Containee)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (Container.asDecl())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (const Stmt *S = Containee.asStmt())
|
||||||
|
if (const Stmt *ContainerS = Container.asStmt()) {
|
||||||
|
while (S) {
|
||||||
|
if (S == ContainerS)
|
||||||
|
return true;
|
||||||
|
S = PDB.getParent(S);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less accurate: compare using source ranges.
|
||||||
|
SourceRange ContainerR = Container.asRange();
|
||||||
|
SourceRange ContaineeR = Containee.asRange();
|
||||||
|
|
||||||
|
SourceManager &SM = PDB.getSourceManager();
|
||||||
|
SourceLocation ContainerRBeg = SM.getInstantiationLoc(ContainerR.getBegin());
|
||||||
|
SourceLocation ContainerREnd = SM.getInstantiationLoc(ContainerR.getEnd());
|
||||||
|
SourceLocation ContaineeRBeg = SM.getInstantiationLoc(ContaineeR.getBegin());
|
||||||
|
SourceLocation ContaineeREnd = SM.getInstantiationLoc(ContaineeR.getEnd());
|
||||||
|
|
||||||
|
unsigned ContainerBegLine = SM.getInstantiationLineNumber(ContainerRBeg);
|
||||||
|
unsigned ContainerEndLine = SM.getInstantiationLineNumber(ContainerREnd);
|
||||||
|
unsigned ContaineeBegLine = SM.getInstantiationLineNumber(ContaineeRBeg);
|
||||||
|
unsigned ContaineeEndLine = SM.getInstantiationLineNumber(ContaineeREnd);
|
||||||
|
|
||||||
|
assert(ContainerBegLine <= ContainerEndLine);
|
||||||
|
assert(ContaineeBegLine <= ContaineeEndLine);
|
||||||
|
|
||||||
|
return (ContainerBegLine <= ContaineeBegLine &&
|
||||||
|
ContainerEndLine >= ContaineeEndLine &&
|
||||||
|
(ContainerBegLine != ContaineeBegLine ||
|
||||||
|
SM.getInstantiationColumnNumber(ContainerRBeg) <=
|
||||||
|
SM.getInstantiationColumnNumber(ContaineeRBeg)) &&
|
||||||
|
(ContainerEndLine != ContaineeEndLine ||
|
||||||
|
SM.getInstantiationColumnNumber(ContainerREnd) >=
|
||||||
|
SM.getInstantiationColumnNumber(ContainerREnd)));
|
||||||
|
}
|
||||||
|
|
||||||
|
PathDiagnosticLocation
|
||||||
|
EdgeBuilder::IgnoreParens(const PathDiagnosticLocation &L) {
|
||||||
|
if (const Expr* E = dyn_cast_or_null<Expr>(L.asStmt()))
|
||||||
|
return PathDiagnosticLocation(E->IgnoreParenCasts(),
|
||||||
|
PDB.getSourceManager());
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
|
||||||
|
if (!PrevLoc.isValid()) {
|
||||||
|
PrevLoc = NewLoc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NewLoc.asLocation() == PrevLoc.asLocation())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// FIXME: Ignore intra-macro edges for now.
|
||||||
|
if (NewLoc.asLocation().getInstantiationLoc() ==
|
||||||
|
PrevLoc.asLocation().getInstantiationLoc())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PD.push_front(new PathDiagnosticControlFlowPiece(NewLoc, PrevLoc));
|
||||||
|
PrevLoc = NewLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
|
||||||
|
const PathDiagnosticLocation &CLoc = getContextLocation(NewLoc);
|
||||||
|
|
||||||
|
while (!CLocs.empty()) {
|
||||||
|
const PathDiagnosticLocation &TopContextLoc = CLocs.back();
|
||||||
|
|
||||||
|
// Is the top location context the same as the one for the new location?
|
||||||
|
if (TopContextLoc == CLoc) {
|
||||||
|
if (alwaysAdd && NewLoc.asLocation() != CLoc.asLocation())
|
||||||
|
rawAddEdge(NewLoc);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containsLocation(TopContextLoc, CLoc)) {
|
||||||
|
if (alwaysAdd)
|
||||||
|
rawAddEdge(NewLoc);
|
||||||
|
|
||||||
|
CLocs.push_back(CLoc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context does not contain the location. Flush it.
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0 && "addEdge should never pop the top context");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdgeBuilder::addContext(const Stmt *S) {
|
||||||
|
if (!S)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PathDiagnosticLocation L(S, PDB.getSourceManager());
|
||||||
|
|
||||||
|
while (!CLocs.empty()) {
|
||||||
|
const PathDiagnosticLocation &TopContextLoc = CLocs.back();
|
||||||
|
|
||||||
|
// Is the top location context the same as the one for the new location?
|
||||||
|
if (TopContextLoc == L)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (containsLocation(TopContextLoc, L)) {
|
||||||
|
// if (const Stmt *S = L.asStmt())
|
||||||
|
// if (isa<Expr>(S))
|
||||||
|
// if (const Stmt *P = PDB.getParent(S))
|
||||||
|
// addContext(PDB.getEnclosingStmtLocation(P).asStmt());
|
||||||
|
|
||||||
|
CLocs.push_back(L);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context does not contain the location. Flush it.
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
CLocs.push_back(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
|
||||||
|
PathDiagnosticBuilder &PDB,
|
||||||
|
const ExplodedNode<GRState> *N) {
|
||||||
|
|
||||||
|
|
||||||
|
EdgeBuilder EB(PD, PDB);
|
||||||
|
|
||||||
|
const ExplodedNode<GRState>* NextNode = N->pred_empty()
|
||||||
|
? NULL : *(N->pred_begin());
|
||||||
|
|
||||||
|
while (NextNode) {
|
||||||
|
N = NextNode;
|
||||||
|
NextNode = GetPredecessorNode(N);
|
||||||
|
ProgramPoint P = N->getLocation();
|
||||||
|
|
||||||
|
// Block edges.
|
||||||
|
if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
|
||||||
|
const CFGBlock &Blk = *BE->getSrc();
|
||||||
|
|
||||||
|
if (const Stmt *Term = Blk.getTerminator())
|
||||||
|
EB.addContext(Term);
|
||||||
|
|
||||||
|
// Only handle blocks with more than 1 statement here, as the blocks
|
||||||
|
// with one statement are handled at BlockEntrances.
|
||||||
|
if (Blk.size() > 1) {
|
||||||
|
const Stmt *S = *Blk.rbegin();
|
||||||
|
EB.addEdge(S);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
|
||||||
|
if (const Stmt* S = BE->getFirstStmt()) {
|
||||||
|
if (IsControlFlowExpr(S))
|
||||||
|
EB.addContext(S);
|
||||||
|
else
|
||||||
|
EB.addEdge(S);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathDiagnosticPiece* p =
|
||||||
|
PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
|
||||||
|
PDB.getBugReporter(), PDB.getNodeMapClosure());
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
EB.addEdge(p->getLocation(), true);
|
||||||
|
PD.push_front(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
static void GenExtAddEdge(PathDiagnostic& PD,
|
static void GenExtAddEdge(PathDiagnostic& PD,
|
||||||
PathDiagnosticBuilder &PDB,
|
PathDiagnosticBuilder &PDB,
|
||||||
PathDiagnosticLocation NewLoc,
|
PathDiagnosticLocation NewLoc,
|
||||||
|
|
@ -930,6 +1188,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Methods for BugType and subclasses.
|
// Methods for BugType and subclasses.
|
||||||
|
|
@ -1337,10 +1596,6 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
|
||||||
GenerateMinimalPathDiagnostic(PD, PDB, N);
|
GenerateMinimalPathDiagnostic(PD, PDB, N);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// After constructing the full PathDiagnostic, do a pass over it to compact
|
|
||||||
// PathDiagnosticPieces that occur within a macro.
|
|
||||||
CompactPathDiagnostic(PD, PDB.getSourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BugReporter::Register(BugType *BT) {
|
void BugReporter::Register(BugType *BT) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue