szepet created this revision.
szepet added reviewers: dcoughlin, NoQ, zaks.anna, xazax.hun, a.sidorin.
Herald added subscribers: dkrupp, baloghadamsoftware, whisperity.

Based on the CFGLoopEntrance element, it is possible to have a CFG driven 
LocationContext update which contains loop information as well.
Updated the loop unrolling feature as well to use purely the LocationContext 
stack and not implement its own.


https://reviews.llvm.org/D41151

Files:
  include/clang/Analysis/AnalysisDeclContext.h
  include/clang/Analysis/ProgramPoint.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
  lib/Analysis/AnalysisDeclContext.cpp
  lib/StaticAnalyzer/Core/CoreEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===================================================================
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -373,7 +373,6 @@
   return 0;
 }
 
-
 void pr34943() {
   for (int i = 0; i < 6L; ++i) {
     clang_analyzer_numTimesReached(); // expected-warning {{6}}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===================================================================
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -13,11 +13,11 @@
 ///
 //===----------------------------------------------------------------------===//
 
-#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
 
 using namespace clang;
 using namespace ento;
@@ -28,56 +28,36 @@
 struct LoopState {
 private:
   enum Kind { Normal, Unrolled } K;
-  const Stmt *LoopStmt;
-  const LocationContext *LCtx;
-  unsigned maxStep;
-  LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
-      : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
+  unsigned MaxStep;
+  LoopState(Kind InK, unsigned N) : K(InK), MaxStep(N) {}
 
 public:
-  static LoopState getNormal(const Stmt *S, const LocationContext *L,
-                             unsigned N) {
-    return LoopState(Normal, S, L, N);
-  }
-  static LoopState getUnrolled(const Stmt *S, const LocationContext *L,
-                               unsigned N) {
-    return LoopState(Unrolled, S, L, N);
-  }
+  static LoopState getNormal(unsigned N) { return LoopState(Normal, N); }
+  static LoopState getUnrolled(unsigned N) { return LoopState(Unrolled, N); }
   bool isUnrolled() const { return K == Unrolled; }
-  unsigned getMaxStep() const { return maxStep; }
-  const Stmt *getLoopStmt() const { return LoopStmt; }
-  const LocationContext *getLocationContext() const { return LCtx; }
+  unsigned getMaxStep() const { return MaxStep; }
   bool operator==(const LoopState &X) const {
-    return K == X.K && LoopStmt == X.LoopStmt;
+    return K == X.K && MaxStep == X.MaxStep;
   }
   void Profile(llvm::FoldingSetNodeID &ID) const {
     ID.AddInteger(K);
-    ID.AddPointer(LoopStmt);
-    ID.AddPointer(LCtx);
-    ID.AddInteger(maxStep);
+    ID.AddInteger(MaxStep);
   }
 };
 
-// The tracked stack of loops. The stack indicates that which loops the
-// simulated element contained by. The loops are marked depending if we decided
-// to unroll them.
-// TODO: The loop stack should not need to be in the program state since it is
-// lexical in nature. Instead, the stack of loops should be tracked in the
-// LocationContext.
-REGISTER_LIST_WITH_PROGRAMSTATE(LoopStack, LoopState)
+// The map of the currently simulated loops which are marked depending if we
+// decided to unroll them.
+REGISTER_MAP_WITH_PROGRAMSTATE(LoopMap, const LoopContext *, LoopState)
 
 namespace clang {
 namespace ento {
 
 static bool isLoopStmt(const Stmt *S) {
   return S && (isa<ForStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S));
 }
 
-ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) {
-  auto LS = State->get<LoopStack>();
-  if (!LS.isEmpty() && LS.getHead().getLoopStmt() == LoopStmt)
-    State = State->set<LoopStack>(LS.getTail());
-  return State;
+ProgramStateRef processLoopEnd(const LoopContext *LC, ProgramStateRef State) {
+  return State->remove<LoopMap>(LC);
 }
 
 static internal::Matcher<Stmt> simpleCondition(StringRef BindName) {
@@ -157,7 +137,8 @@
                  hasUnaryOperand(declRefExpr(
                      to(varDecl(allOf(equalsBoundNode("initVarName"),
                                       hasType(isInteger())))))))),
-             unless(hasBody(hasSuspiciousStmt("initVarName")))).bind("forLoop");
+             unless(hasBody(hasSuspiciousStmt("initVarName"))))
+      .bind("forLoop");
 }
 
 static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) {
@@ -236,59 +217,55 @@
     ProgramPoint P = N->getLocation();
     if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>())
       S = BE->getBlock()->getTerminator();
+    else if (Optional<LoopEnter> LE = P.getAs<LoopEnter>())
+      S = LE->getLoopStmt();
 
     if (S == LoopStmt)
       return false;
 
     N = N->getFirstPred();
   }
-
   llvm_unreachable("Reached root without encountering the previous step");
 }
 
-// updateLoopStack is called on every basic block, therefore it needs to be fast
-ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
-                                ExplodedNode *Pred, unsigned maxVisitOnPath) {
+// updateLoopStates is called on every basic block, therefore it needs to be
+// fast
+ProgramStateRef updateLoopStates(const LoopContext *LoopCtx, ASTContext &ASTCtx,
+                                 ExplodedNode *Pred, unsigned MaxVisitOnPath) {
   auto State = Pred->getState();
-  auto LCtx = Pred->getLocationContext();
+  auto LM = State->get<LoopMap>();
+  auto LoopStmt = LoopCtx->getLoopStmt();
 
-  if (!isLoopStmt(LoopStmt))
-    return State;
+  assert((!LM.contains(LoopCtx) ||
+          (LM.contains(LoopCtx) &&
+           Pred->getLocation().getKind() == ProgramPoint::BlockEdgeKind)) &&
+         "LoopEnter Block encountered for an already entered loop");
 
-  auto LS = State->get<LoopStack>();
-  if (!LS.isEmpty() && LoopStmt == LS.getHead().getLoopStmt() &&
-      LCtx == LS.getHead().getLocationContext()) {
-    if (LS.getHead().isUnrolled() && madeNewBranch(Pred, LoopStmt)) {
-      State = State->set<LoopStack>(LS.getTail());
-      State = State->add<LoopStack>(
-          LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
-    }
-    return State;
-  }
-  unsigned maxStep;
-  if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred, maxStep)) {
-    State = State->add<LoopStack>(
-        LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
-    return State;
-  }
+  if (LM.contains(LoopCtx) && LM.lookup(LoopCtx)->isUnrolled() &&
+      madeNewBranch(Pred, LoopStmt))
+    return State->set<LoopMap>(LoopCtx, LoopState::getNormal(MaxVisitOnPath));
 
-  unsigned outerStep = (LS.isEmpty() ? 1 : LS.getHead().getMaxStep());
+  if (LM.contains(LoopCtx))
+    return State;
 
-  unsigned innerMaxStep = maxStep * outerStep;
-  if (innerMaxStep > MAXIMUM_STEP_UNROLLED)
-    State = State->add<LoopStack>(
-        LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
+  unsigned MaxStep;
+  if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred, MaxStep))
+    return State->set<LoopMap>(LoopCtx, LoopState::getNormal(MaxVisitOnPath));
+
+  const auto OuterLoopCtx =
+      cast_or_null<LoopContext>(Pred->getLocationContext()->getCurrentLoop());
+  unsigned OuterStep =
+      (OuterLoopCtx ? LM.lookup(OuterLoopCtx)->getMaxStep() : 1);
+  unsigned InnerMaxStep = MaxStep * OuterStep;
+  if (InnerMaxStep > MAXIMUM_STEP_UNROLLED)
+    return State->set<LoopMap>(LoopCtx, LoopState::getNormal(MaxVisitOnPath));
   else
-    State = State->add<LoopStack>(
-        LoopState::getUnrolled(LoopStmt, LCtx, innerMaxStep));
-  return State;
+    return State->set<LoopMap>(LoopCtx, LoopState::getUnrolled(InnerMaxStep));
 }
 
-bool isUnrolledState(ProgramStateRef State) {
-  auto LS = State->get<LoopStack>();
-  if (LS.isEmpty() || !LS.getHead().isUnrolled())
-    return false;
-  return true;
-}
-}
+bool isUnrolledLoopContext(const LoopContext *LC, ProgramStateRef State) {
+  auto LM = State->get<LoopMap>();
+  return LM.contains(LC) && LM.lookup(LC)->isUnrolled();
 }
+} // namespace ento
+} // namespace clang
Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -312,7 +312,12 @@
 
     // Step 4: Generate the CallExit and leave the callee's context.
     // CleanedNodes -> CEENode
-    CallExitEnd Loc(calleeCtx, callerCtx);
+    const LocationContext *ExitContext = calleeCtx->getParent();
+    while (!dyn_cast<StackFrameContext>(ExitContext) &&
+           !dyn_cast<LoopContext>(ExitContext)) {
+      ExitContext = ExitContext->getParent();
+    }
+    CallExitEnd Loc(calleeCtx, ExitContext);
     bool isNew;
     ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState();
     ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew);
@@ -408,13 +413,18 @@
 
   const LocationContext *CurLC = Pred->getLocationContext();
   const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame();
-  const LocationContext *ParentOfCallee = CallerSFC;
+
+  while (!dyn_cast<StackFrameContext>(CurLC) && !dyn_cast<LoopContext>(CurLC)) {
+    CurLC = CurLC->getParent();
+  }
+
+  const LocationContext *ParentOfCallee = CurLC;
   if (Call.getKind() == CE_Block &&
       !cast<BlockCall>(Call).isConversionFromLambda()) {
     const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
     assert(BR && "If we have the block definition we should have its region");
     AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
-    ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
+    ParentOfCallee = BlockCtx->getBlockInvocationContext(CurLC,
                                                          cast<BlockDecl>(D),
                                                          BR);
   }
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -367,6 +367,9 @@
     case CFGElement::LoopExit:
       ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred);
       return;
+    case CFGElement::LoopEntrance:
+      ProcessLoopEntrance(E.castAs<CFGLoopEntrance>().getLoopStmt(), Pred);
+      return;
     case CFGElement::LifetimeEnds:
       return;
   }
@@ -512,20 +515,49 @@
   Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
 }
 
-void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
+void ExprEngine::ProcessLoopEntrance(const Stmt *LoopStmt, ExplodedNode *Pred) {
   PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
-                                S->getLocStart(),
-                                "Error evaluating end of the loop");
+                                LoopStmt->getLocStart(),
+                                "Error evaluating enter of the loop");
+
   ExplodedNodeSet Dst;
-  Dst.Add(Pred);
   NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
   ProgramStateRef NewState = Pred->getState();
 
-  if(AMgr.options.shouldUnrollLoops())
-    NewState = processLoopEnd(S, NewState);
+  const LocationContext *PrevLC = Pred->getLocationContext();
+  const LoopContext *LoopCtx =
+      PrevLC->getAnalysisDeclContext()->getLoopContext(PrevLC, LoopStmt);
+  LoopEnter LE(LoopStmt, LoopCtx);
 
-  LoopExit PP(S, Pred->getLocationContext());
-  Bldr.generateNode(PP, NewState, Pred);
+  if (AMgr.options.shouldUnrollLoops()) {
+    NewState = updateLoopStates(LoopCtx, AMgr.getASTContext(), Pred,
+                                AMgr.getAnalyzerOptions().maxBlockVisitOnPath);
+  }
+
+  Bldr.generateNode(LE, NewState, Pred);
+  // Enqueue the new nodes onto the work list.
+  Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
+void ExprEngine::ProcessLoopExit(const Stmt *LoopStmt, ExplodedNode *Pred) {
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+                                LoopStmt->getLocStart(),
+                                "Error evaluating end of the loop");
+
+  ExplodedNodeSet Dst;
+  NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+  ProgramStateRef NewState = Pred->getState();
+  const LocationContext *NewLCtx = Pred->getLocationContext();
+
+  if (NewLCtx->getKind() == LocationContext::Loop &&
+      cast<LoopContext>(NewLCtx)->getLoopStmt() == LoopStmt) {
+    if (AMgr.options.shouldUnrollLoops()) {
+      NewState = processLoopEnd(cast<LoopContext>(NewLCtx), NewState);
+    }
+    NewLCtx = NewLCtx->getParent();
+  }
+  LoopExit LE(LoopStmt, NewLCtx);
+  Bldr.generateNode(LE, NewState, Pred);
   // Enqueue the new nodes onto the work list.
   Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
 }
@@ -1556,23 +1588,31 @@
                                          NodeBuilderWithSinks &nodeBuilder,
                                          ExplodedNode *Pred) {
   PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
+
   // If we reach a loop which has a known bound (and meets
   // other constraints) then consider completely unrolling it.
   if(AMgr.options.shouldUnrollLoops()) {
-    unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
-    const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
-    if (Term) {
-      ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
-                                                 Pred, maxBlockVisitOnPath);
+    do {
+      unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
+      const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
+
+      if (!(Term &&
+            (isa<ForStmt>(Term) || isa<WhileStmt>(Term) || isa<DoStmt>(Term))))
+        break;
+
+      ProgramStateRef NewState =
+          updateLoopStates(Pred->getLocationContext()->getCurrentLoop(),
+                           AMgr.getASTContext(), Pred, maxBlockVisitOnPath);
       if (NewState != Pred->getState()) {
         ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred);
         if (!UpdatedNode)
           return;
         Pred = UpdatedNode;
       }
-    }
-    // Is we are inside an unrolled loop then no need the check the counters.
-    if(isUnrolledState(Pred->getState()))
+    } while (false);
+    // If we are inside an unrolled loop then no need the check the counters.
+    if (isUnrolledLoopContext(Pred->getLocationContext()->getCurrentLoop(),
+                              Pred->getState()))
       return;
   }
 
@@ -2750,6 +2790,12 @@
         break;
       }
 
+      case ProgramPoint::LoopEnterKind: {
+        LoopEnter LE = Loc.castAs<LoopEnter>();
+        Out << "LoopEnter: " << LE.getLoopStmt()->getStmtClassName();
+        break;
+      }
+
       case ProgramPoint::PreImplicitCallKind: {
         ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
         Out << "PreCall: ";
@@ -2900,6 +2946,11 @@
         Out << "Entering scope";
         // FIXME: Add more info once ScopeContext is activated.
         break;
+      case LocationContext::Loop:
+        Out << "Entering loop: ";
+        cast<LoopContext>(LC)->getLoopStmt()->printPretty(
+            Out, nullptr, PrintingPolicy(LangOptions()));
+        break;
       }
       Out << "\\l";
     }
Index: lib/StaticAnalyzer/Core/CoreEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -275,6 +275,7 @@
              Loc.getAs<PostInitializer>() ||
              Loc.getAs<PostImplicitCall>() ||
              Loc.getAs<CallExitEnd>() ||
+             Loc.getAs<LoopEnter>() ||
              Loc.getAs<LoopExit>());
       HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
       break;
@@ -332,8 +333,10 @@
   ExplodedNodeSet dstNodes;
   BlockEntrance BE(Blk, Pred->getLocationContext());
   NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE);
+  const LocationContext *NewLC = Pred->getLocationContext();
   SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
 
+  BE = BlockEntrance(Blk, NewLC);
   // Auto-generate a node.
   if (!nodeBuilder.hasGeneratedNodes()) {
     nodeBuilder.generateNode(Pred->State, Pred);
@@ -568,6 +571,7 @@
   // Do not create extra nodes. Move to the next CFG element.
   if (N->getLocation().getAs<PostInitializer>() ||
       N->getLocation().getAs<PostImplicitCall>()||
+      N->getLocation().getAs<LoopEnter>() ||
       N->getLocation().getAs<LoopExit>()) {
     WList->enqueue(N, Block, Idx+1);
     return;
@@ -637,7 +641,8 @@
   for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) {
     ExplodedNode *N = *I;
     // If we are in an inlined call, generate CallExitBegin node.
-    if (N->getLocationContext()->getParent()) {
+    if (isa<StackFrameContext>(N->getLocationContext()) &&
+        N->getLocationContext()->getParent()) {
       N = generateCallExitBeginNode(N, RS);
       if (N)
         WList->enqueue(N);
Index: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp
+++ lib/Analysis/AnalysisDeclContext.cpp
@@ -313,6 +313,12 @@
   return getLocationContextManager().getStackFrame(this, Parent, S, Blk, Idx);
 }
 
+const LoopContext *
+AnalysisDeclContext::getLoopContext(const LocationContext *Parent,
+                                    const Stmt *LoopStmt) {
+  return getLocationContextManager().getLoopContext(this, Parent, LoopStmt);
+}
+
 const BlockInvocationContext *
 AnalysisDeclContext::getBlockInvocationContext(const LocationContext *parent,
                                                const clang::BlockDecl *BD,
@@ -365,6 +371,10 @@
   Profile(ID, getAnalysisDeclContext(), getParent(), Enter);
 }
 
+void LoopContext::Profile(llvm::FoldingSetNodeID &ID) {
+  Profile(ID, getAnalysisDeclContext(), getParent(), LoopStmt);
+}
+
 void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
   Profile(ID, getAnalysisDeclContext(), getParent(), BD, ContextData);
 }
@@ -415,6 +425,13 @@
   return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
 }
 
+const LoopContext *
+LocationContextManager::getLoopContext(AnalysisDeclContext *Ctx,
+                                       const LocationContext *Parent,
+                                       const Stmt *LoopStmt) {
+  return getLocationContext<LoopContext, Stmt>(Ctx, Parent, LoopStmt);
+}
+
 const BlockInvocationContext *
 LocationContextManager::getBlockInvocationContext(AnalysisDeclContext *ctx,
                                                   const LocationContext *parent,
@@ -447,6 +464,16 @@
   return nullptr;
 }
 
+const LoopContext *LocationContext::getCurrentLoop() const {
+  const LocationContext *LC = this;
+  while (LC) {
+    if (const LoopContext *LoopCtx = dyn_cast<LoopContext>(LC))
+      return LoopCtx;
+    LC = LC->getParent();
+  }
+  return nullptr;
+}
+
 bool LocationContext::inTopFrame() const {
   return getCurrentStackFrame()->inTopFrame();
 }
@@ -484,6 +511,11 @@
                    << cast<BlockInvocationContext>(LCtx)->getContextData()
                    << ")\n";
       break;
+    case Loop:
+      OS << Indent << "    (loop context: "
+                   << cast<LoopContext>(LCtx)->getLoopStmt()->getStmtClassName()
+                   << ")\n";
+      break;
     }
   }
 }
Index: include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
@@ -34,15 +34,15 @@
 
 /// Returns if the given State indicates that is inside a completely unrolled
 /// loop.
-bool isUnrolledState(ProgramStateRef State);
+bool isUnrolledLoopContext(const LoopContext *LC, ProgramStateRef State);
 
 /// Updates the stack of loops contained by the ProgramState.
-ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
-                                ExplodedNode* Pred, unsigned maxVisitOnPath);
+ProgramStateRef updateLoopStates(const LoopContext *LC, ASTContext &ASTCtx,
+                                 ExplodedNode *Pred, unsigned MaxVisitOnPath);
 
 /// Updates the given ProgramState. In current implementation it removes the top
 /// element of the stack of loops.
-ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State);
+ProgramStateRef processLoopEnd(const LoopContext *LC, ProgramStateRef State);
 
 } // end namespace ento
 } // end namespace clang
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -196,6 +196,8 @@
 
   void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
 
+  void ProcessLoopEntrance(const Stmt *S, ExplodedNode *Pred);
+
   void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
 
   void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
@@ -219,7 +221,7 @@
   void processCFGBlockEntrance(const BlockEdge &L,
                                NodeBuilderWithSinks &nodeBuilder,
                                ExplodedNode *Pred) override;
- 
+
   /// ProcessBranch - Called by CoreEngine.  Used to generate successor
   ///  nodes by processing the 'effects' of a branch condition.
   void processBranch(const Stmt *Condition, const Stmt *Term, 
Index: include/clang/Analysis/ProgramPoint.h
===================================================================
--- include/clang/Analysis/ProgramPoint.h
+++ include/clang/Analysis/ProgramPoint.h
@@ -83,6 +83,7 @@
               PostImplicitCallKind,
               MinImplicitCallKind = PreImplicitCallKind,
               MaxImplicitCallKind = PostImplicitCallKind,
+              LoopEnterKind,
               LoopExitKind,
               EpsilonKind};
 
@@ -615,7 +616,7 @@
 ///
 /// The call exit is simulated with a sequence of nodes, which occur between
 /// CallExitBegin and CallExitEnd. The following operations occur between the
-/// two program points:
+/// two preogram points:
 /// - CallExitBegin
 /// - Bind the return value
 /// - Run Remove dead bindings (to clean up the dead symbols from the callee).
@@ -655,6 +656,23 @@
   }
 };
 
+class LoopEnter : public ProgramPoint {
+public:
+  LoopEnter(const Stmt *LoopStmt, const LocationContext *LC)
+      : ProgramPoint(LoopStmt, nullptr, LoopEnterKind, LC) {}
+
+  const Stmt *getLoopStmt() const {
+    return static_cast<const Stmt *>(getData1());
+  }
+
+private:
+  friend class ProgramPoint;
+  LoopEnter() {}
+  static bool isKind(const ProgramPoint &Location) {
+    return Location.getKind() == LoopEnterKind;
+  }
+};
+
 /// Represents a point when we exit a loop.
 /// When this ProgramPoint is encountered we can be sure that the symbolic
 /// execution of the corresponding LoopStmt is finished on the given path.
Index: include/clang/Analysis/AnalysisDeclContext.h
===================================================================
--- include/clang/Analysis/AnalysisDeclContext.h
+++ include/clang/Analysis/AnalysisDeclContext.h
@@ -36,6 +36,7 @@
 class LocationContextManager;
 class StackFrameContext;
 class BlockInvocationContext;
+class LoopContext;
 class AnalysisDeclContextManager;
 class LocationContext;
 
@@ -185,7 +186,10 @@
                                          const Stmt *S,
                                          const CFGBlock *Blk,
                                          unsigned Idx);
-  
+
+  const LoopContext *getLoopContext(const LocationContext *Parent,
+                                    const Stmt *LoopStmt);
+
   const BlockInvocationContext *
   getBlockInvocationContext(const LocationContext *parent,
                             const BlockDecl *BD,
@@ -214,7 +218,7 @@
 
 class LocationContext : public llvm::FoldingSetNode {
 public:
-  enum ContextKind { StackFrame, Scope, Block };
+  enum ContextKind { StackFrame, Scope, Block, Loop };
 
 private:
   ContextKind Kind;
@@ -260,6 +264,8 @@
 
   const StackFrameContext *getCurrentStackFrame() const;
 
+  const LoopContext *getCurrentLoop() const;
+
   /// Return true if the current LocationContext has no caller context.
   virtual bool inTopFrame() const;
 
@@ -320,6 +326,31 @@
   }
 };
 
+class LoopContext : public LocationContext {
+  const Stmt *LoopStmt;
+
+  friend class LocationContextManager;
+  LoopContext(AnalysisDeclContext *Ctx, const LocationContext *Parent,
+              const Stmt *LS)
+      : LocationContext(Loop, Ctx, Parent), LoopStmt(LS) {}
+
+public:
+  ~LoopContext() override {}
+
+  const Stmt *getLoopStmt() const { return LoopStmt; }
+
+  void Profile(llvm::FoldingSetNodeID &ID) override;
+
+  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *Ctx,
+                      const LocationContext *Parent, const Stmt *LS) {
+    ProfileCommon(ID, Scope, Ctx, Parent, LS);
+  }
+
+  static bool classof(const LocationContext *Ctx) {
+    return Ctx->getKind() == Loop;
+  }
+};
+
 class ScopeContext : public LocationContext {
   const Stmt *Enter;
 
@@ -390,7 +421,11 @@
   const ScopeContext *getScope(AnalysisDeclContext *ctx,
                                const LocationContext *parent,
                                const Stmt *s);
-  
+
+  const LoopContext *getLoopContext(AnalysisDeclContext *Ctx,
+                                    const LocationContext *Parent,
+                                    const Stmt *LoopStmt);
+
   const BlockInvocationContext *
   getBlockInvocationContext(AnalysisDeclContext *ctx,
                             const LocationContext *parent,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to