baloghadamsoftware updated this revision to Diff 255922.
baloghadamsoftware added a comment.

Next attempt.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77229/new/

https://reviews.llvm.org/D77229

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/test/Analysis/iterator-modeling.cpp

Index: clang/test/Analysis/iterator-modeling.cpp
===================================================================
--- clang/test/Analysis/iterator-modeling.cpp
+++ clang/test/Analysis/iterator-modeling.cpp
@@ -28,7 +28,7 @@
 void clang_analyzer_eval(bool);
 void clang_analyzer_warnIfReached();
 
-void begin(const std::vector<int> &v) {
+/*void begin(const std::vector<int> &v) {
   auto i = v.begin();
 
   clang_analyzer_eval(clang_analyzer_iterator_container(i) == &v); // expected-warning{{TRUE}}
@@ -1773,7 +1773,7 @@
   clang_analyzer_express(clang_analyzer_iterator_position(i3)); // expected-warning{{$i1 + 2}} FIXME: Should be $i1 + 1
   // clang_analyzer_express(clang_analyzer_iterator_position(i5)); FIXME: expect warning $i1 + 1
   clang_analyzer_express(clang_analyzer_iterator_position(i4)); // expected-warning{{$FL.end()}}
-}
+  }*/
 
 struct simple_iterator_base {
   simple_iterator_base();
@@ -1812,7 +1812,7 @@
   }
 }
 
-void iter_diff(std::vector<int> &V) {
+/*void iter_diff(std::vector<int> &V) {
   auto i0 = V.begin(), i1 = V.end();
   ptrdiff_t len = i1 - i0; // no-crash
 }
@@ -1880,3 +1880,4 @@
 // CHECK-NEXT:     "i1 : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}"
 // CHECK-NEXT:   ]}
 }
+*/
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -109,6 +109,96 @@
   return LValue;
 }
 
+Optional<SVal> ExprEngine::retrieveFromConstructionContext(
+    ProgramStateRef State, const LocationContext *LCtx,
+    const ConstructionContext *CC) const {
+  if (CC) {
+    switch (CC->getKind()) {
+    case ConstructionContext::CXX17ElidedCopyVariableKind:
+    case ConstructionContext::SimpleVariableKind: {
+      const auto *DSCC = cast<VariableConstructionContext>(CC);
+      const auto *DS = DSCC->getDeclStmt();
+      return getObjectUnderConstruction(State, DS, LCtx);
+    }
+    case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
+    case ConstructionContext::SimpleConstructorInitializerKind: {
+      const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
+      const auto *Init = ICC->getCXXCtorInitializer();
+      return getObjectUnderConstruction(State, Init, LCtx);
+    }
+    case ConstructionContext::SimpleReturnedValueKind:
+    case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
+      const StackFrameContext *SFC = LCtx->getStackFrame();
+      if (const LocationContext *CallerLCtx = SFC->getParent()) {
+        auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()]
+                       .getAs<CFGCXXRecordTypedCall>();
+        if (!RTC) {
+          // We were unable to find the correct construction context for the
+          // call in the parent stack frame. This is equivalent to not being
+          // able to find construction context at all.
+          break;
+        }
+        if (isa<BlockInvocationContext>(CallerLCtx)) {
+          // Unwrap block invocation contexts. They're mostly part of
+          // the current stack frame.
+          CallerLCtx = CallerLCtx->getParent();
+          assert(!isa<BlockInvocationContext>(CallerLCtx));
+        }
+        return retrieveFromConstructionContext(
+          State, CallerLCtx, RTC->getConstructionContext());
+      }
+      break;
+    }
+    case ConstructionContext::ElidedTemporaryObjectKind: {
+      assert(AMgr.getAnalyzerOptions().ShouldElideConstructors);
+      const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
+      Optional<SVal> RetVal = retrieveFromConstructionContext(
+          State, LCtx, TCC->getConstructionContextAfterElision());
+      if (RetVal.hasValue())
+        return RetVal;
+      
+      LLVM_FALLTHROUGH;
+    }
+    case ConstructionContext::SimpleTemporaryObjectKind: {
+      const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
+      const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr();
+      Optional<SVal> RetVal;
+      if (BTE) {
+        RetVal = getObjectUnderConstruction(State, BTE, LCtx);
+        if (RetVal.hasValue())
+          return RetVal;
+      }
+      
+      const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr();
+      if (MTE)
+        RetVal = getObjectUnderConstruction(State, MTE, LCtx);
+
+      return RetVal;
+    }
+    case ConstructionContext::ArgumentKind: {
+      const auto *ACC = cast<ArgumentConstructionContext>(CC);
+      const Expr *E = ACC->getCallLikeExpr();
+      unsigned Idx = ACC->getIndex();
+      if (const auto *CE = dyn_cast<CallExpr>(E)) {
+        return getObjectUnderConstruction(State, {CE, Idx}, LCtx);
+      } else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) {
+        return getObjectUnderConstruction(State, {CCE, Idx}, LCtx);
+      } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
+        return getObjectUnderConstruction(State, {ME, Idx}, LCtx);
+      } else if (const auto *BTE = ACC->getCXXBindTemporaryExpr()) {
+        return getObjectUnderConstruction(State, BTE, LCtx);
+      }
+
+      LLVM_FALLTHROUGH;
+    }
+    default:
+      return None;
+    }
+  }
+
+  return None;
+}
+
 std::pair<ProgramStateRef, SVal> ExprEngine::handleConstructionContext(
     const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
     const ConstructionContext *CC, EvalCallOptions &CallOpts) {
@@ -137,7 +227,16 @@
     case ConstructionContext::SimpleConstructorInitializerKind: {
       const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
       const auto *Init = ICC->getCXXCtorInitializer();
-      assert(Init->isAnyMemberInitializer());
+      if (!Init->isAnyMemberInitializer()) {
+        const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
+        Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
+                                                  LCtx->getStackFrame());
+        SVal ThisVal = State->getSVal(ThisPtr);
+        SVal BaseVal =
+          getStoreManager().evalDerivedToBase(ThisVal, E->getType(),
+                                              Init->isBaseVirtual());
+        return std::make_pair(State, BaseVal);
+      }
       const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
       Loc ThisPtr =
       SVB.getCXXThis(CurCtor, LCtx->getStackFrame());
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -466,7 +466,7 @@
   // incorrect handling of temporaries bound to default parameters.
   assert(!State->get<ObjectsUnderConstruction>(Key) ||
          Key.getItem().getKind() ==
-             ConstructionContextItem::TemporaryDestructorKind);
+         ConstructionContextItem::TemporaryDestructorKind);
   return State->set<ObjectsUnderConstruction>(Key, V);
 }
 
@@ -602,7 +602,6 @@
                            const LocationContext *LCtx, const char *NL,
                            unsigned int Space, bool IsDot) const {
   Indent(Out, Space, IsDot) << "\"constructing_objects\": ";
-
   if (LCtx && !State->get<ObjectsUnderConstruction>().isEmpty()) {
     ++Space;
     Out << '[' << NL;
Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -257,6 +257,143 @@
   return VR;
 }
 
+const ConstructionContext
+*CallEvent::getConstructionContext(unsigned BlockCount) const {
+  const CFGBlock *Block;
+  unsigned Index;
+
+  if (const StackFrameContext *StackFrame = getCalleeStackFrame(BlockCount)) {
+    Block = StackFrame->getCallSiteBlock();
+    if (!Block) {
+      llvm::errs()<<"No Call Site Block.\n";
+      return nullptr;
+    }
+
+    Index = StackFrame->getIndex();
+  } else {
+    CFGStmtMap *Map =
+      getLocationContext()->getAnalysisDeclContext()->getCFGStmtMap();
+    Block = Map->getBlock(getOriginExpr());
+    if (!Block) {
+      llvm::errs()<<"No Call Site Block.\n";
+      return nullptr;
+    }
+
+    for (Index = 0; Index < Block->size(); ++Index) {
+      if (const auto CS = (*Block)[Index].getAs<CFGStmt>()) {
+        if (CS->getStmt() == getOriginExpr())
+          break;
+      }
+    }
+  }
+
+  if (Index == Block->size()) {
+    llvm::errs()<<"    Stmt not found!\n";
+    return nullptr;
+  }
+
+  if(const auto Ctor = (*Block)[Index].getAs<CFGConstructor>()) {
+    return Ctor->getConstructionContext();
+  }
+
+  if (const auto RecCall = (*Block)[Index].getAs<CFGCXXRecordTypedCall>()) {
+    return RecCall->getConstructionContext();
+  }
+
+  llvm::errs()<<"    Neither a Constructor nor a CFG C++ Record-Typed Call!\n";
+  return nullptr;
+}
+
+Optional<SVal>
+CallEvent::getReturnValueUnderConstruction(ExprEngine &Engine,
+                                           unsigned BlockCount) const {
+  const auto *CC = getConstructionContext(BlockCount);
+  if (!CC) {
+    llvm::errs()<<"  No construction context!!!\n";
+    return None;
+  }
+
+  llvm::errs()<<"  Retrieving Original\n";
+  Optional<SVal> RetVal =
+    Engine.retrieveFromConstructionContext(getState(), getLocationContext(),
+                                           CC);
+  if (RetVal.hasValue())
+    return RetVal;
+
+  ExprEngine::EvalCallOptions CallOpts;
+  ProgramStateRef State;
+  SVal NewVal;
+  llvm::errs()<<"  Handling New\n";
+  std::tie(State, NewVal) =
+    Engine.handleConstructionContext(getOriginExpr(), getState(),
+                                     getLocationContext(), CC, CallOpts);
+  return NewVal;
+}
+
+const ConstructionContext
+*CallEvent::getArgConstructionContext(unsigned Index,
+                                      unsigned BlockCount) const {
+  const CFGBlock *Block;
+  unsigned CFGIndex;
+
+  CFGStmtMap *Map =
+    getLocationContext()->getAnalysisDeclContext()->getCFGStmtMap();
+  Block = Map->getBlock(getArgExpr(Index));
+  if (!Block) {
+    llvm::errs()<<"No Call Site Block.\n";
+    return nullptr;
+  }
+
+  for (CFGIndex = 0; CFGIndex < Block->size(); ++CFGIndex) {
+    if (const auto CS = (*Block)[CFGIndex].getAs<CFGStmt>()) {
+      if (CS->getStmt() == getArgExpr(Index))
+        break;
+    }
+  }
+
+  if (CFGIndex == Block->size()) {
+    llvm::errs()<<"    Stmt not found!\n";
+    return nullptr;
+  }
+
+  if(const auto Ctor = (*Block)[CFGIndex].getAs<CFGConstructor>()) {
+    return Ctor->getConstructionContext();
+  }
+
+  if (const auto RecCall = (*Block)[CFGIndex].getAs<CFGCXXRecordTypedCall>()) {
+    return RecCall->getConstructionContext();
+  }
+
+  llvm::errs()<<"    Neither a Constructor nor a CFG C++ Record-Typed Call!\n";
+  return nullptr;
+}
+
+Optional<SVal>
+CallEvent::getArgUnderConstruction(unsigned Index, ExprEngine &Engine,
+                                   unsigned BlockCount) const {
+  const auto *CC = getArgConstructionContext(Index, BlockCount);
+  if (!CC) {
+    llvm::errs()<<"  No construction context!!!\n";
+    return None;
+  }
+
+  llvm::errs()<<"  Retrieving Original\n";
+  Optional<SVal> RetVal =
+    Engine.retrieveFromConstructionContext(getState(), getLocationContext(),
+                                           CC);
+  if (RetVal.hasValue())
+    return RetVal;
+
+  ExprEngine::EvalCallOptions CallOpts;
+  ProgramStateRef State;
+  SVal NewVal;
+  llvm::errs()<<"  Handling New\n";
+  std::tie(State, NewVal) =
+    Engine.handleConstructionContext(getArgExpr(Index), getState(),
+                                     getLocationContext(), CC, CallOpts);
+  return NewVal;
+}
+
 /// Returns true if a type is a pointer-to-const or reference-to-const
 /// with no further indirection.
 static bool isPointerToConst(QualType Ty) {
Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -83,8 +83,8 @@
 namespace {
 
 class IteratorModeling
-    : public Checker<check::PostCall, check::PostStmt<MaterializeTemporaryExpr>,
-                     check::Bind, check::LiveSymbols, check::DeadSymbols> {
+    : public Checker<check::PostCall, check::Bind, check::LiveSymbols,
+                     check::DeadSymbols> {
 
   using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *,
                                                SVal, SVal, SVal) const;
@@ -146,8 +146,6 @@
   void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
   void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
   void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
-  void checkPostStmt(const MaterializeTemporaryExpr *MTE,
-                     CheckerContext &C) const;
   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
 };
@@ -156,8 +154,6 @@
 ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
 ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
                               SymbolRef Sym2, bool Equal);
-bool isBoundThroughLazyCompoundVal(const Environment &Env,
-                                   const MemRegion *Reg);
 const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call);
 
 } // namespace
@@ -190,14 +186,25 @@
 
   auto State = C.getState();
 
+  llvm::errs()<<"Generic PostCall\n";
+  Optional<SVal> RetVal = Call.getReturnValue();
+  llvm::errs()<<"Original RetVal: "<<*RetVal<<"\n";
+  if (RetVal->getAs<nonloc::LazyCompoundVal>()) {
+    RetVal =
+      Call.getReturnValueUnderConstruction(C.getExprEngine(), C.blockCount());
+    if (!RetVal.hasValue())
+      return;
+  }
+  llvm::errs()<<"Updated RetVal: "<<*RetVal<<"\n";
+
   // Already bound to container?
-  if (getIteratorPosition(State, Call.getReturnValue()))
+  if (getIteratorPosition(State, *RetVal))
     return;
 
   // Copy-like and move constructors
   if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
     if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
-      State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
+      State = setIteratorPosition(State, *RetVal, *Pos);
       if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
         State = removeIteratorPosition(State, Call.getArgSVal(0));
       }
@@ -214,7 +221,7 @@
   for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
     if (isIteratorType(Call.getArgExpr(i)->getType())) {
       if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
-        assignToContainer(C, OrigExpr, Call.getReturnValue(),
+        assignToContainer(C, OrigExpr, *RetVal,
                           Pos->getContainer());
         return;
       }
@@ -225,6 +232,11 @@
 void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S,
                                  CheckerContext &C) const {
   auto State = C.getState();
+  if (Val.getAs<nonloc::LazyCompoundVal>())
+    return;
+
+  llvm::errs()<<"Bind Old: "<<Val<<"\n";
+  llvm::errs()<<"Bind New: "<<Loc<<"\n";
   const auto *Pos = getIteratorPosition(State, Val);
   if (Pos) {
     State = setIteratorPosition(State, Loc, *Pos);
@@ -238,26 +250,18 @@
   }
 }
 
-void IteratorModeling::checkPostStmt(const MaterializeTemporaryExpr *MTE,
-                                     CheckerContext &C) const {
-  /* Transfer iterator state to temporary objects */
-  auto State = C.getState();
-  const auto *Pos = getIteratorPosition(State, C.getSVal(MTE->getSubExpr()));
-  if (!Pos)
-    return;
-  State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
-  C.addTransition(State);
-}
-
 void IteratorModeling::checkLiveSymbols(ProgramStateRef State,
                                         SymbolReaper &SR) const {
+  llvm::errs()<<"CheckLive\n";
   // Keep symbolic expressions of iterator positions alive
   auto RegionMap = State->get<IteratorRegionMap>();
   for (const auto &Reg : RegionMap) {
     const auto Offset = Reg.second.getOffset();
     for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
-      if (isa<SymbolData>(*i))
+      if (isa<SymbolData>(*i)) {
+        llvm::errs()<<"  Keeping position "<<*i<<".\n";
         SR.markLive(*i);
+      }
   }
 
   auto SymbolMap = State->get<IteratorSymbolMap>();
@@ -272,18 +276,16 @@
 
 void IteratorModeling::checkDeadSymbols(SymbolReaper &SR,
                                         CheckerContext &C) const {
+  llvm::errs()<<"CheckDead\n";
   // Cleanup
   auto State = C.getState();
 
   auto RegionMap = State->get<IteratorRegionMap>();
   for (const auto &Reg : RegionMap) {
     if (!SR.isLiveRegion(Reg.first)) {
-      // The region behind the `LazyCompoundVal` is often cleaned up before
-      // the `LazyCompoundVal` itself. If there are iterator positions keyed
-      // by these regions their cleanup must be deferred.
-      if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
-        State = State->remove<IteratorRegionMap>(Reg.first);
-      }
+      llvm::errs()<<"  Removing position for "<<Reg.first<<" (Pos: "<<Reg.second.getOffset()<<").\n";
+      llvm::errs()<<"    Base Region: "<<Reg.first->getBaseRegion()<<"\n";
+      State = State->remove<IteratorRegionMap>(Reg.first);
     }
   }
 
@@ -301,61 +303,72 @@
 IteratorModeling::handleOverloadedOperator(CheckerContext &C,
                                            const CallEvent &Call,
                                            OverloadedOperatorKind Op) const {
-    if (isSimpleComparisonOperator(Op)) {
-      const auto *OrigExpr = Call.getOriginExpr();
-      if (!OrigExpr)
-        return;
+  const auto *OrigExpr = Call.getOriginExpr();
+  if (!OrigExpr)
+    return;
 
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        handleComparison(C, OrigExpr, Call.getReturnValue(),
-                         InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
-        return;
-      }
+  llvm::errs()<<"Overloaded Operator\n";
+  Optional<SVal> RetVal = Call.getReturnValue();
+  llvm::errs()<<"Original RetVal: "<<*RetVal<<"\n";
+  if (RetVal->getAs<nonloc::LazyCompoundVal>()) {
+    RetVal =
+      Call.getReturnValueUnderConstruction(C.getExprEngine(), C.blockCount());
+    if (!RetVal.hasValue())
+      return;
+  }
+  llvm::errs()<<"Updated RetVal: "<<*RetVal<<"\n";
 
-      handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
-                         Call.getArgSVal(1), Op);
+  if (isSimpleComparisonOperator(Op)) {
+    const auto *OrigExpr = Call.getOriginExpr();
+    if (!OrigExpr)
       return;
-    } else if (isRandomIncrOrDecrOperator(Op)) {
-      const auto *OrigExpr = Call.getOriginExpr();
-      if (!OrigExpr)
-        return;
 
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        if (Call.getNumArgs() >= 1 &&
-              Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
-          handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
-                                 InstCall->getCXXThisVal(), Call.getArgSVal(0));
-          return;
-        }
-      } else {
-        if (Call.getNumArgs() >= 2 &&
-              Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
-          handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
-                                 Call.getArgSVal(0), Call.getArgSVal(1));
-          return;
-        }
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleComparison(C, OrigExpr, *RetVal,
+                       InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
+      return;
+    }
+
+    handleComparison(C, OrigExpr, *RetVal, Call.getArgSVal(0),
+                     Call.getArgSVal(1), Op);
+    return;
+  } else if (isRandomIncrOrDecrOperator(Op)) {
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      if (Call.getNumArgs() >= 1 &&
+          Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
+        handleRandomIncrOrDecr(C, OrigExpr, Op, *RetVal,
+                               InstCall->getCXXThisVal(), Call.getArgSVal(0));
+        return;
       }
-    } else if (isIncrementOperator(Op)) {
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
-                        Call.getNumArgs());
+    } else {
+      if (Call.getNumArgs() >= 2 &&
+          Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
+        handleRandomIncrOrDecr(C, OrigExpr, Op, *RetVal,
+                               Call.getArgSVal(0), Call.getArgSVal(1));
         return;
       }
-
-      handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
+    }
+  } else if (isIncrementOperator(Op)) {
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleIncrement(C, *RetVal, InstCall->getCXXThisVal(),
                       Call.getNumArgs());
       return;
-    } else if (isDecrementOperator(Op)) {
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
-                        Call.getNumArgs());
-        return;
-      }
+    }
 
-      handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
-                        Call.getNumArgs());
+    handleIncrement(C, *RetVal, Call.getArgSVal(0),
+                    Call.getNumArgs());
+    return;
+  } else if (isDecrementOperator(Op)) {
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleDecrement(C, *RetVal, InstCall->getCXXThisVal(),
+                      Call.getNumArgs());
       return;
     }
+
+    handleDecrement(C, *RetVal, Call.getArgSVal(0),
+                    Call.getNumArgs());
+    return;
+  }
 }
 
 void
@@ -363,8 +376,19 @@
                                             const CallEvent &Call,
                                             const Expr *OrigExpr,
                                             const AdvanceFn *Handler) const {
+  llvm::errs()<<"Advance-like Function\n";
+  Optional<SVal> RetVal = Call.getReturnValue();
+  llvm::errs()<<"Original RetVal: "<<*RetVal<<"\n";
+  if (RetVal->getAs<nonloc::LazyCompoundVal>()) {
+    RetVal =
+      Call.getReturnValueUnderConstruction(C.getExprEngine(), C.blockCount());
+    if (!RetVal.hasValue())
+      return;
+  }
+  llvm::errs()<<"Updated RetVal: "<<*RetVal<<"\n";
+
   if (!C.wasInlined) {
-    (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
+    (this->**Handler)(C, OrigExpr, *RetVal,
                       Call.getArgSVal(0), Call.getArgSVal(1));
     return;
   }
@@ -375,7 +399,7 @@
   if (IdInfo) {
     if (IdInfo->getName() == "advance") {
       if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) {
-        (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
+        (this->**Handler)(C, OrigExpr, *RetVal,
                           Call.getArgSVal(0), Call.getArgSVal(1));
       }
     }
@@ -647,8 +671,6 @@
     return State->remove<IteratorRegionMap>(Reg);
   } else if (const auto Sym = Val.getAsSymbol()) {
     return State->remove<IteratorSymbolMap>(Sym);
-  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
-    return State->remove<IteratorRegionMap>(LCVal->getRegion());
   }
   return nullptr;
 }
@@ -685,18 +707,6 @@
   return NewState;
 }
 
-bool isBoundThroughLazyCompoundVal(const Environment &Env,
-                                   const MemRegion *Reg) {
-  for (const auto &Binding : Env) {
-    if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
-      if (LCVal->getRegion() == Reg)
-        return true;
-    }
-  }
-
-  return false;
-}
-
 const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call) {
   while (Node) {
     ProgramPoint PP = Node->getLocation();
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
+++ clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
@@ -153,26 +153,24 @@
 
 const IteratorPosition *getIteratorPosition(ProgramStateRef State,
                                             const SVal &Val) {
+  llvm::errs()<<"  Getting position for "<<Val<<".\n";
   if (auto Reg = Val.getAsRegion()) {
     Reg = Reg->getMostDerivedObjectRegion();
     return State->get<IteratorRegionMap>(Reg);
   } else if (const auto Sym = Val.getAsSymbol()) {
     return State->get<IteratorSymbolMap>(Sym);
-  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
-    return State->get<IteratorRegionMap>(LCVal->getRegion());
   }
   return nullptr;
 }
 
 ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
                                     const IteratorPosition &Pos) {
+  llvm::errs()<<"  Setting position for "<<Val<<" (Pos: "<<Pos.getOffset()<<").\n";
   if (auto Reg = Val.getAsRegion()) {
     Reg = Reg->getMostDerivedObjectRegion();
     return State->set<IteratorRegionMap>(Reg, Pos);
   } else if (const auto Sym = Val.getAsSymbol()) {
     return State->set<IteratorSymbolMap>(Sym, Pos);
-  } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
-    return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
   }
   return nullptr;
 }
Index: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -163,6 +163,17 @@
   if (!Func)
     return;
 
+  llvm::errs()<<"Container PostCall\n";
+  Optional<SVal> RetVal = Call.getReturnValue();
+  llvm::errs()<<"Original RetVal: "<<*RetVal<<"\n";
+  if (RetVal->getAs<nonloc::LazyCompoundVal>()) {
+    RetVal =
+      Call.getReturnValueUnderConstruction(C.getExprEngine(), C.blockCount());
+    if (!RetVal.hasValue())
+      return;
+  }
+  llvm::errs()<<"Updated RetVal: "<<*RetVal<<"\n";
+
   if (Func->isOverloadedOperator()) {
     const auto Op = Func->getOverloadedOperator();
     if (Op == OO_Equal) {
@@ -188,7 +199,23 @@
 
       const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call);
       if (Handler1) {
-        (this->**Handler1)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
+        Optional<SVal> Arg = Call.getArgSVal(0);
+        llvm::errs()<<"Original Arg(0): "<<*Arg<<"\n";
+        if (Arg->getAs<nonloc::LazyCompoundVal>()) {
+          const MemRegion *ArgLoc = Call.getParameterLocation(0,
+                                                              C.blockCount());
+          if (ArgLoc) {
+            Arg = loc::MemRegionVal(ArgLoc);
+          } else {
+            Arg = Call.getArgUnderConstruction(0, C.getExprEngine(),
+                                               C.blockCount());
+            if (!Arg.hasValue())
+              return;
+          }
+        }
+        llvm::errs()<<"Updated Arg(0): "<<*Arg<<"\n";
+
+        (this->**Handler1)(C, InstCall->getCXXThisVal(), *Arg);
         return;
       }
 
@@ -204,13 +231,13 @@
         return;
 
       if (isBeginCall(Func)) {
-        handleBegin(C, OrigExpr, Call.getReturnValue(),
+        handleBegin(C, OrigExpr, *RetVal,
                     InstCall->getCXXThisVal());
         return;
       }
 
       if (isEndCall(Func)) {
-        handleEnd(C, OrigExpr, Call.getReturnValue(),
+        handleEnd(C, OrigExpr, *RetVal,
                   InstCall->getCXXThisVal());
         return;
       }
@@ -580,9 +607,13 @@
 
   auto State = C.getState();
   const auto *Pos = getIteratorPosition(State, Iter);
-  if (!Pos)
+  llvm::errs()<<"Inserting to: "<<Iter;
+  if (!Pos) {
+    llvm::errs()<<" (No Pos)\n";
     return;
+  }
 
+  llvm::errs()<<" (Pos: "<<Pos->getOffset()<<")\n";
   // For deque-like containers invalidate all iterator positions. For
   // vector-like containers invalidate iterator positions after the insertion.
   if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -686,6 +686,21 @@
                        const CallEvent &Call,
                        const EvalCallOptions &CallOpts = {});
 
+  /// Update the program state with all the path-sensitive information
+  /// that's necessary to perform construction of an object with a given
+  /// syntactic construction context. If the construction context is unavailable
+  /// or unusable for any reason, a dummy temporary region is returned, and the
+  /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts.
+  /// Returns the updated program state and the new object's this-region.
+  std::pair<ProgramStateRef, SVal> handleConstructionContext(
+      const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
+      const ConstructionContext *CC, EvalCallOptions &CallOpts);
+
+  ///
+  Optional<SVal> retrieveFromConstructionContext(
+      ProgramStateRef State, const LocationContext *LCtx,
+      const ConstructionContext *CC) const;
+
 private:
   ProgramStateRef finishArgumentConstruction(ProgramStateRef State,
                                              const CallEvent &Call);
@@ -804,16 +819,6 @@
   /// constructing into an existing region.
   const CXXConstructExpr *findDirectConstructorForCurrentCFGElement();
 
-  /// Update the program state with all the path-sensitive information
-  /// that's necessary to perform construction of an object with a given
-  /// syntactic construction context. If the construction context is unavailable
-  /// or unusable for any reason, a dummy temporary region is returned, and the
-  /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts.
-  /// Returns the updated program state and the new object's this-region.
-  std::pair<ProgramStateRef, SVal> handleConstructionContext(
-      const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
-      const ConstructionContext *CC, EvalCallOptions &CallOpts);
-
   /// Common code that handles either a CXXConstructExpr or a
   /// CXXInheritedCtorInitExpr.
   void handleConstructor(const Expr *E, ExplodedNode *Pred,
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -52,6 +52,10 @@
            "We should not call the checkers on an empty state.");
   }
 
+  ExprEngine &getExprEngine() {
+    return Eng;
+  }
+
   AnalysisManager &getAnalysisManager() {
     return Eng.getAnalysisManager();
   }
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -431,6 +431,19 @@
     return CallArgumentIndex;
   }
 
+  /// If the call returns a C++ record type then the call has a construction
+  /// context from where the region of its return value can be retrieved.
+  const ConstructionContext *getConstructionContext(unsigned BlockCount) const;
+
+  const ConstructionContext
+  *getArgConstructionContext(unsigned Index, unsigned BlockCount) const;
+
+  Optional<SVal> getArgUnderConstruction(unsigned Index, ExprEngine &Engine,
+                                         unsigned BlockCount) const;
+
+  Optional<SVal> getReturnValueUnderConstruction(ExprEngine &Engine,
+                                                 unsigned BlockCount) const;
+
   // Iterator access to formal parameters and their types.
 private:
   struct GetTypeFn {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to