aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/BugReporter.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2013-02-08 19:51:43 +0000
committerTed Kremenek <kremenek@apple.com>2013-02-08 19:51:43 +0000
commit8185674528423e2504a1fae35c28c24104846510 (patch)
tree34c9c7933d95842fbaa034276f2ed7cf40048aed /lib/StaticAnalyzer/Core/BugReporter.cpp
parent5a56e1bdfbf57787314dd44a27318964eaa2cf39 (diff)
Teach BugReporter (extensive diagnostics) to emit a diagnostic when a loop body is skipped.
Fixes <rdar://problem/12322528>. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174736 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporter.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp54
1 files changed, 51 insertions, 3 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 772a78706a..f4d50708dd 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -1294,7 +1294,25 @@ static void reversePropagateInterestingSymbols(BugReport &R,
}
}
}
-
+
+/// Return true if the terminator is a loop and the destination is the
+/// false branch.
+static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) {
+ switch (Term->getStmtClass()) {
+ case Stmt::ForStmtClass:
+ case Stmt::WhileStmtClass:
+ break;
+ default:
+ // Note that we intentionally do not include do..while here.
+ return false;
+ }
+
+ // Did we take the false branch?
+ const CFGBlock *Src = BE->getSrc();
+ assert(Src->succ_size() == 2);
+ return (*(Src->succ_begin()+1) == BE->getDst());
+}
+
static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
@@ -1304,6 +1322,10 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
StackDiagVector CallStack;
InterestingExprs IE;
+ // Record the last "looping back" diagnostic. This is used
+ // for determining if we should emit a diagnostic for skipped loops.
+ std::pair<const Stmt *, PathDiagnosticEventPiece *> LastLoopDiagnostic(0, 0);
+
const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
@@ -1415,6 +1437,12 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
"Looping back to the head of the loop");
p->setPrunable(true);
+ // Record the loop diagnostic for later consultation. We can
+ // use this to determine whether or not to emit a "skipped loop"
+ // event.
+ LastLoopDiagnostic.first = Loop;
+ LastLoopDiagnostic.second = p;
+
EB.addEdge(p->getLocation(), true);
PD.getActivePath().push_front(p);
@@ -1424,9 +1452,29 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
EB.addEdge(BL);
}
}
-
- if (const Stmt *Term = BE->getSrc()->getTerminator())
+
+ if (const Stmt *Term = BE->getSrc()->getTerminator()) {
+ // Are we jumping past the loop body without ever executing the
+ // loop (because the condition was false)?
+ if (isLoopJumpPastBody(Term, BE) &&
+ !PD.getActivePath().empty() &&
+ PD.getActivePath().front() != LastLoopDiagnostic.second &&
+ Term != LastLoopDiagnostic.first)
+ {
+ PathDiagnosticLocation L(Term, SM, PDB.LC);
+ PathDiagnosticEventPiece *PE =
+ new PathDiagnosticEventPiece(L,
+ "Loop body executed 0 times");
+ PE->setPrunable(true);
+ LastLoopDiagnostic.first = 0;
+ LastLoopDiagnostic.second = 0;
+
+ EB.addEdge(PE->getLocation(), true);
+ PD.getActivePath().push_front(PE);
+ }
+
EB.addContext(Term);
+ }
break;
}