diff options
author | Ted Kremenek <kremenek@apple.com> | 2013-02-08 19:51:43 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2013-02-08 19:51:43 +0000 |
commit | 8185674528423e2504a1fae35c28c24104846510 (patch) | |
tree | 34c9c7933d95842fbaa034276f2ed7cf40048aed /lib/StaticAnalyzer/Core/BugReporter.cpp | |
parent | 5a56e1bdfbf57787314dd44a27318964eaa2cf39 (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.cpp | 54 |
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; } |