- Changed PathDiagnosticPiece::getLocation() to return a PathDiagnosticLocation
instead of a FullSourceLoc. This resulted in a bunch of small edits in various
clients.
- Updated BugReporter to include an alternate PathDiagnostic generation
algorithm for PathDiagnosticClients desiring more control-flow pieces.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68193 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 1d1c2fa..f54200b 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -154,6 +154,14 @@
PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
+ PathDiagnosticLocation
+ getEnclosingStmtLocation(const PathDiagnosticLocation &L) {
+ if (const Stmt *S = L.asStmt())
+ return getEnclosingStmtLocation(S);
+
+ return L;
+ }
+
PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const {
return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive;
}
@@ -196,13 +204,21 @@
PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
assert(S && "Null Stmt* passed to getEnclosingStmtLocation");
ParentMap &P = getParentMap();
- while (isa<Expr>(S)) {
+
+ while (isa<DeclStmt>(S) || isa<Expr>(S)) {
const Stmt *Parent = P.getParent(S);
if (!Parent)
break;
switch (Parent->getStmtClass()) {
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *B = cast<BinaryOperator>(Parent);
+ if (B->isLogicalOp())
+ return PathDiagnosticLocation(S, SMgr);
+ break;
+ }
+
case Stmt::CompoundStmtClass:
case Stmt::StmtExprClass:
return PathDiagnosticLocation(S, SMgr);
@@ -674,7 +690,7 @@
End = PDB.getEnclosingStmtLocation(S);
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Loop condition is true. Entering loop body"));
+ "Loop condition is true. Entering loop body"));
}
break;
@@ -688,10 +704,10 @@
if (*(Src->succ_begin()+1) == Dst)
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking false branch"));
+ "Taking false branch"));
else
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking true branch"));
+ "Taking true branch"));
break;
}
@@ -715,6 +731,151 @@
}
//===----------------------------------------------------------------------===//
+// "Extensive" PathDiagnostic generation.
+//===----------------------------------------------------------------------===//
+
+static bool IsControlFlowExpr(const Stmt *S) {
+ const Expr *E = dyn_cast<Expr>(S);
+
+ if (!E)
+ return false;
+
+ E = E->IgnoreParenCasts();
+
+ if (isa<ConditionalOperator>(E))
+ return true;
+
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E))
+ if (B->isLogicalOp())
+ return true;
+
+ return false;
+}
+
+static void GenExtAddEdge(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ PathDiagnosticLocation NewLoc,
+ PathDiagnosticLocation &PrevLoc,
+ PathDiagnosticLocation UpdateLoc) {
+
+ if (const Stmt *S = NewLoc.asStmt()) {
+ if (IsControlFlowExpr(S))
+ return;
+ }
+
+
+ if (!PrevLoc.isValid()) {
+ PrevLoc = NewLoc;
+ return;
+ }
+
+ if (NewLoc == PrevLoc)
+ return;
+
+ PD.push_front(new PathDiagnosticControlFlowPiece(NewLoc, PrevLoc));
+ PrevLoc = UpdateLoc;
+}
+
+static bool IsNestedDeclStmt(const Stmt *S, ParentMap &PM) {
+ const DeclStmt *DS = dyn_cast<DeclStmt>(S);
+
+ if (!DS)
+ return false;
+
+ const Stmt *Parent = PM.getParent(DS);
+ if (!Parent)
+ return false;
+
+ if (const ForStmt *FS = dyn_cast<ForStmt>(Parent))
+ return FS->getInit() == DS;
+
+ // FIXME: In the future IfStmt/WhileStmt may contain DeclStmts in their condition.
+// if (const IfStmt *IF = dyn_cast<IfStmt>(Parent))
+// return IF->getCond() == DS;
+//
+// if (const WhileStmt *WS = dyn_cast<WhileStmt>(Parent))
+// return WS->getCond() == DS;
+
+ return false;
+}
+
+static void GenExtAddEdge(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ const PathDiagnosticLocation &NewLoc,
+ PathDiagnosticLocation &PrevLoc) {
+ GenExtAddEdge(PD, PDB, NewLoc, PrevLoc, NewLoc);
+}
+
+static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ const ExplodedNode<GRState> *N) {
+
+ SourceManager& SMgr = PDB.getSourceManager();
+ const ExplodedNode<GRState>* NextNode = N->pred_empty()
+ ? NULL : *(N->pred_begin());
+
+ PathDiagnosticLocation PrevLoc;
+
+ 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()) {
+ const Stmt *Cond = Blk.getTerminatorCondition();
+
+ if (!Cond || !IsControlFlowExpr(Cond)) {
+ GenExtAddEdge(PD, PDB, PathDiagnosticLocation(Term, SMgr), PrevLoc);
+ continue;
+ }
+ }
+
+ // 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();
+
+ // We don't add control-flow edges for DeclStmt's that appear in
+ // the condition of if/while/for or are control-flow merge expressions.
+ if (!IsControlFlowExpr(S) && !IsNestedDeclStmt(S, PDB.getParentMap())) {
+ GenExtAddEdge(PD, PDB, PathDiagnosticLocation(S, SMgr), PrevLoc);
+ }
+ }
+
+ continue;
+ }
+
+ if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+ if (const Stmt* S = BE->getFirstStmt()) {
+ if (!IsControlFlowExpr(S) && !IsNestedDeclStmt(S, PDB.getParentMap())) {
+ // Are we jumping with the same enclosing statement?
+ if (PrevLoc.isValid() && PDB.getEnclosingStmtLocation(S) ==
+ PDB.getEnclosingStmtLocation(PrevLoc)) {
+ continue;
+ }
+
+ GenExtAddEdge(PD, PDB, PDB.getEnclosingStmtLocation(S), PrevLoc);
+ }
+ }
+
+ continue;
+ }
+
+ PathDiagnosticPiece* p =
+ PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
+ PDB.getBugReporter(), PDB.getNodeMapClosure());
+
+ if (p) {
+ GenExtAddEdge(PD, PDB, p->getLocation(), PrevLoc);
+ PD.push_front(p);
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
// Methods for BugType and subclasses.
//===----------------------------------------------------------------------===//
BugType::~BugType() {}
@@ -993,7 +1154,7 @@
for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
// Get the location of the PathDiagnosticPiece.
- const FullSourceLoc Loc = I->getLocation();
+ const FullSourceLoc Loc = I->getLocation().asLocation();
// Determine the instantiation location, which is the location we group
// related PathDiagnosticPieces.
@@ -1114,6 +1275,8 @@
switch (PDB.getGenerationScheme()) {
case PathDiagnosticClient::Extensive:
+ GenerateExtensivePathDiagnostic(PD,PDB, N);
+ break;
case PathDiagnosticClient::Minimal:
GenerateMinimalPathDiagnostic(PD, PDB, N);
break;
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 6e43ec5..c9917da 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -2635,13 +2635,8 @@
os << "+0 retain count (non-owning reference).";
}
- FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
- PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str());
-
- if (Expr* Exp = dyn_cast<Expr>(S))
- P->addRange(Exp->getSourceRange());
-
- return P;
+ PathDiagnosticLocation Pos(S, BR.getContext().getSourceManager());
+ return new PathDiagnosticEventPiece(Pos, os.str());
}
// Gather up the effects that were performed on the object at this
@@ -2797,7 +2792,7 @@
return 0; // We have nothing to say!
Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
- FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
+ PathDiagnosticLocation Pos(S, BR.getContext().getSourceManager());
PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str());
// Add the range by scanning the children of the statement for any bindings
@@ -2958,7 +2953,9 @@
assert(LeakN && S && "No leak site found.");
// Generate the diagnostic.
- FullSourceLoc L(S->getLocStart(), SMgr);
+ // FIXME: We need to do a better job at determing the leak site, e.g., at
+ // the end of function bodies.
+ PathDiagnosticLocation L(S, SMgr);
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
index 02fe165..69b11fb 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -140,6 +140,7 @@
//===----------------------------------------------------------------------===//
FullSourceLoc PathDiagnosticLocation::asLocation() const {
+ assert(isValid());
// Note that we want a 'switch' here so that the compiler can warn us in
// case we add more cases.
switch (K) {
@@ -154,6 +155,7 @@
}
SourceRange PathDiagnosticLocation::asRange() const {
+ assert(isValid());
// Note that we want a 'switch' here so that the compiler can warn us in
// case we add more cases.
switch (K) {