diff options
author | Ted Kremenek <kremenek@apple.com> | 2013-02-22 05:45:33 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2013-02-22 05:45:33 +0000 |
commit | b04a2387ac23adfa063de03844cb16c0d77fb405 (patch) | |
tree | a2a91dcbf5fe5d6ec05b48a52d7b50d16619b3ee /lib/StaticAnalyzer/Core/BugReporter.cpp | |
parent | 671b3219c2be00ef8f26234ec993816c3ba56a4f (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.cpp | 82 |
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); } |