aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/BugReporter.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2013-02-22 05:45:33 +0000
committerTed Kremenek <kremenek@apple.com>2013-02-22 05:45:33 +0000
commitb04a2387ac23adfa063de03844cb16c0d77fb405 (patch)
treea2a91dcbf5fe5d6ec05b48a52d7b50d16619b3ee /lib/StaticAnalyzer/Core/BugReporter.cpp
parent671b3219c2be00ef8f26234ec993816c3ba56a4f (diff)
[analyzer] Implement "Loop executed 0 times" diagnostic correctly.
Fixes <rdar://problem/13236549> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175863 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporter.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp82
1 files changed, 62 insertions, 20 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 8556089fe3..9191fdea2d 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -1295,6 +1295,10 @@ static void reversePropagateInterestingSymbols(BugReport &R,
}
}
+//===----------------------------------------------------------------------===//
+// Functions for determining if a loop was executed 0 times.
+//===----------------------------------------------------------------------===//
+
/// Return true if the terminator is a loop and the destination is the
/// false branch.
static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) {
@@ -1313,6 +1317,52 @@ static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) {
return (*(Src->succ_begin()+1) == BE->getDst());
}
+static bool isContainedByStmt(ParentMap &PM, const Stmt *S, const Stmt *SubS) {
+ while (SubS) {
+ if (SubS == S)
+ return true;
+ SubS = PM.getParent(SubS);
+ }
+ return false;
+}
+
+static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term,
+ const ExplodedNode *N) {
+ while (N) {
+ Optional<StmtPoint> SP = N->getLocation().getAs<StmtPoint>();
+ if (SP) {
+ const Stmt *S = SP->getStmt();
+ if (!isContainedByStmt(PM, Term, S))
+ return S;
+ }
+ N = GetPredecessorNode(N);
+ }
+ return 0;
+}
+
+static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
+ const Stmt *LoopBody = 0;
+ switch (Term->getStmtClass()) {
+ case Stmt::ForStmtClass: {
+ const ForStmt *FS = cast<ForStmt>(Term);
+ if (isContainedByStmt(PM, FS->getInc(), S))
+ return true;
+ LoopBody = FS->getBody();
+ break;
+ }
+ case Stmt::WhileStmtClass:
+ LoopBody = cast<WhileStmt>(Term)->getBody();
+ break;
+ default:
+ return false;
+ }
+ return isContainedByStmt(PM, LoopBody, S);
+}
+
+//===----------------------------------------------------------------------===//
+// Top-level logic for generating extensive path diagnostics.
+//===----------------------------------------------------------------------===//
+
static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
@@ -1322,11 +1372,6 @@ 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((Stmt*)0, (PathDiagnosticEventPiece*)0);
-
const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
@@ -1438,12 +1483,6 @@ 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);
@@ -1454,26 +1493,29 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
}
}
- if (const Stmt *Term = BE->getSrc()->getTerminator()) {
+ const CFGBlock *BSrc = BE->getSrc();
+ ParentMap &PM = PDB.getParentMap();
+
+ if (const Stmt *Term = BSrc->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)
- {
+ !isInLoopBody(PM,
+ getStmtBeforeCond(PM,
+ BSrc->getTerminatorCondition(),
+ N),
+ Term)) {
PathDiagnosticLocation L(Term, SM, PDB.LC);
PathDiagnosticEventPiece *PE =
- new PathDiagnosticEventPiece(L,
- "Loop body executed 0 times");
+ 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);
}
+ // In any case, add the terminator as the current statement
+ // context for control edges.
EB.addContext(Term);
}