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

`isIterator()` updated because it did not work perfectly with the refactored 
`handleBegin()` after rebase. (Why did it work before the rebase?) The problem 
was that it only looked for the necessary operators in the actual class but not 
in its bases.


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

https://reviews.llvm.org/D76590

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/container-modeling.cpp
  clang/test/Analysis/diagnostics/explicit-suppression.cpp
  clang/test/Analysis/iterator-modeling.cpp
  clang/test/Analysis/smart-ptr-text-output.cpp
  clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp

Index: clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
===================================================================
--- clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
+++ clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
@@ -51,22 +51,65 @@
 TEST(TestReturnValueUnderConstructionChecker,
      ReturnValueUnderConstructionChecker) {
   EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
-                  R"(class C {
-                     public:
-                       C(int nn): n(nn) {}
-                       virtual ~C() {}
-                     private:
-                       int n;
-                     };
-
-                     C returnC(int m) {
-                       C c(m);
-                       return c;
-                     }
-
-                     void foo() {
-                       C c = returnC(1); 
-                     })"));
+      R"(class C {
+         public:
+           C(int nn): n(nn) {}
+           virtual ~C() {}
+         private:
+           int n;
+         };
+
+         C returnC(int m) {
+           C c(m);
+           return c;
+         }
+
+         void foo() {
+           C c = returnC(1);
+         })"));
+
+  EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
+      R"(class C {
+         public:
+           C(int nn): n(nn) {}
+           explicit C(): C(0) {}
+           virtual ~C() {}
+         private:
+           int n;
+         };
+
+         C returnC() {
+           C c;
+           return c;
+         }
+
+         void foo() {
+           C c = returnC();
+         })"));
+
+  EXPECT_TRUE(runCheckerOnCode<addTestReturnValueUnderConstructionChecker>(
+      R"(class C {
+         public:
+           C(int nn): n(nn) {}
+           virtual ~C() {}
+         private:
+           int n;
+         };
+
+         class D: public C {
+         public:
+           D(int nn): C(nn) {}
+           virtual ~D() {}
+         };
+
+         D returnD(int m) {
+           D d(m);
+           return d;
+         }
+
+         void foo() {
+           D d = returnD(1); 
+         })"));
 }
 
 } // namespace
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===================================================================
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -80,7 +80,7 @@
 void derefOnStdSwappedNullPtr() {
   std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
   std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:987 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
   // expected-note@-1 {{Calling 'swap<A>'}}
   // expected-note@-2 {{Returning from 'swap<A>'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
Index: clang/test/Analysis/iterator-modeling.cpp
===================================================================
--- clang/test/Analysis/iterator-modeling.cpp
+++ clang/test/Analysis/iterator-modeling.cpp
@@ -2026,6 +2026,55 @@
     ++i0;
 }
 
+template <typename T>
+struct delegated_ctor_iterator {
+  delegated_ctor_iterator(const T&, int);
+  delegated_ctor_iterator(const T& t) : delegated_ctor_iterator(t, 0) {}
+  delegated_ctor_iterator operator++();
+  delegated_ctor_iterator operator++(int);
+  T& operator*();
+};
+
+template <typename T>
+struct container_with_delegated_ctor_iterator {
+  typedef delegated_ctor_iterator<T> iterator;
+  iterator begin() const { return delegated_ctor_iterator<T>(T()); }
+};
+
+void
+test_delegated_ctor_iterator(
+    const container_with_delegated_ctor_iterator<int> &c) {
+  auto i = c.begin(); // no-crash
+  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
+  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin()}}
+}
+
+template <typename T>
+struct base_ctor_iterator {
+  base_ctor_iterator(const T&);
+  base_ctor_iterator operator++();
+  base_ctor_iterator operator++(int);
+  T& operator*();
+};
+
+template <typename T>
+struct derived_ctor_iterator: public base_ctor_iterator<T> {
+  derived_ctor_iterator(const T& t) : base_ctor_iterator<T>(t) {}
+};
+
+template <typename T>
+struct container_with_derived_ctor_iterator {
+  typedef derived_ctor_iterator<T> iterator;
+  iterator begin() const { return derived_ctor_iterator<T>(T()); }
+};
+
+void
+test_derived_ctor_iterator(const container_with_derived_ctor_iterator<int> &c) {
+  auto i = c.begin();
+  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
+  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin()}}
+}
+
 void clang_analyzer_printState();
 
 void print_state(std::vector<int> &V) {
Index: clang/test/Analysis/diagnostics/explicit-suppression.cpp
===================================================================
--- clang/test/Analysis/diagnostics/explicit-suppression.cpp
+++ clang/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -19,6 +19,6 @@
 void testCopyNull(C *I, C *E) {
   std::copy(I, E, (C *)0);
 #ifndef SUPPRESSED
-  // expected-warning@../Inputs/system-header-simulator-cxx.h:709 {{Called C++ object pointer is null}}
+  // expected-warning@../Inputs/system-header-simulator-cxx.h:717 {{Called C++ object pointer is null}}
 #endif
 }
Index: clang/test/Analysis/container-modeling.cpp
===================================================================
--- clang/test/Analysis/container-modeling.cpp
+++ clang/test/Analysis/container-modeling.cpp
@@ -16,6 +16,12 @@
 void clang_analyzer_eval(bool);
 void clang_analyzer_warnIfReached();
 
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+    unsigned int __line, __const char *__function)
+     __attribute__ ((__noreturn__));
+#define assert(expr) \
+  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
 void begin(const std::vector<int> &V) {
   V.begin();
 
@@ -56,6 +62,40 @@
                                                                // expected-note@-1{{TRUE}}
 }
 
+////////////////////////////////////////////////////////////////////////////////
+///
+/// C O N T A I N E R   C A P A C I T Y
+///
+////////////////////////////////////////////////////////////////////////////////
+
+/// empty()
+
+void empty(const std::vector<int> &V) {
+  for (auto n: V) {}
+  clang_analyzer_eval(clang_analyzer_container_begin(V) ==
+                      clang_analyzer_container_end(V));
+  // expected-warning@-2{{TRUE}} expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{TRUE}} expected-note@-3   {{FALSE}}
+}
+
+void non_empty1(const std::vector<int> &V) {
+  assert(!V.empty()); // expected-note{{'?' condition is true}}
+  for (auto n: V) {}
+  clang_analyzer_eval(clang_analyzer_container_begin(V) ==
+                      clang_analyzer_container_end(V));
+  // expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{FALSE}}
+}
+
+void non_empty2(const std::vector<int> &V) {
+  for (auto n: V) {}
+  assert(!V.empty()); // expected-note{{'?' condition is true}}
+  clang_analyzer_eval(clang_analyzer_container_begin(V) ==
+                      clang_analyzer_container_end(V));
+  // expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{FALSE}}
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 ///
 /// C O N T A I N E R   M O D I F I E R S
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===================================================================
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -344,6 +344,8 @@
     const T& front() const { return *begin(); }
     T& back() { return *(end() - 1); }
     const T& back() const { return *(end() - 1); }
+
+    bool empty() const;
   };
   
   template<typename T>
@@ -415,6 +417,8 @@
     const T& front() const { return *begin(); }
     T& back() { return *--end(); }
     const T& back() const { return *--end(); }
+
+    bool empty() const;
   };
 
   template<typename T>
@@ -496,6 +500,8 @@
     const T& front() const { return *begin(); }
     T& back() { return *(end() - 1); }
     const T& back() const { return *(end() - 1); }
+
+    bool empty() const;
   };
 
   template<typename T>
@@ -560,6 +566,8 @@
 
     T& front() { return *begin(); }
     const T& front() const { return *begin(); }
+
+    bool empty() const;
   };
 
   template <typename CharT>
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -132,10 +132,11 @@
     case ConstructionContext::SimpleConstructorInitializerKind: {
       const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
       const auto *Init = ICC->getCXXCtorInitializer();
-      assert(Init->isAnyMemberInitializer());
       const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
       Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame());
       SVal ThisVal = State->getSVal(ThisPtr);
+      if (Init->isBaseInitializer() || Init->isDelegatingInitializer())
+        return ThisVal;
 
       const ValueDecl *Field;
       SVal FieldVal;
@@ -364,6 +365,8 @@
     case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
     case ConstructionContext::SimpleConstructorInitializerKind: {
       const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
+      const auto *Init = ICC->getCXXCtorInitializer();
+      assert(Init->isAnyMemberInitializer());
       return addObjectUnderConstruction(State, ICC->getCXXCtorInitializer(),
                                         LCtx, V);
     }
Index: clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -24,12 +24,12 @@
 namespace {
 
 class STLAlgorithmModeling : public Checker<eval::Call> {
-  bool evalFind(CheckerContext &C, const CallExpr *CE) const;
+  void evalFind(CheckerContext &C, const CallExpr *CE, SVal Begin,
+                SVal End) const;
 
-  void Find(CheckerContext &C, const CallExpr *CE, unsigned paramNum) const;
-
-  using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &,
-                                                const CallExpr *) const;
+  using FnCheck = void (STLAlgorithmModeling::*)(CheckerContext &,
+                                                 const CallExpr *, SVal Begin,
+                                                 SVal End) const;
 
   const CallDescriptionMap<FnCheck> Callbacks = {
     {{{"std", "find"}, 3}, &STLAlgorithmModeling::evalFind},
@@ -67,51 +67,45 @@
 
 bool STLAlgorithmModeling::evalCall(const CallEvent &Call,
                                     CheckerContext &C) const {
-  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
-  if (!CE)
-    return false;
-
-  const FnCheck *Handler = Callbacks.lookup(Call);
-  if (!Handler)
-    return false;
-
-  return (this->**Handler)(C, CE);
-}
-
-bool STLAlgorithmModeling::evalFind(CheckerContext &C,
-                                    const CallExpr *CE) const {
   // std::find()-like functions either take their primary range in the first
   // two parameters, or if the first parameter is "execution policy" then in
   // the second and third. This means that the second parameter must always be
   // an iterator.
-  if (!isIteratorType(CE->getArg(1)->getType()))
+  if (Call.getNumArgs() < 2 || !isIteratorType(Call.getArgExpr(1)->getType()))
     return false;
 
   // If no "execution policy" parameter is used then the first argument is the
-  // beginning of the range.
-  if (isIteratorType(CE->getArg(0)->getType())) {
-    Find(C, CE, 0);
-    return true;
+  // beginning of the range. If "execution policy" parmeter is used then the
+  // third argument is the end of the range.
+  unsigned ArgNum = 0;
+  if (!isIteratorType(Call.getArgExpr(0)->getType())) {
+    if (Call.getNumArgs() < 3 || !isIteratorType(Call.getArgExpr(2)->getType()))
+      return false;
+    ArgNum = 1;
   }
 
-  // If "execution policy" parameter is used then the second argument is the
-  // beginning of the range.
-  if (isIteratorType(CE->getArg(2)->getType())) {
-    Find(C, CE, 1);
-    return true;
-  }
+  SVal ArgB = getIteratorArg(Call, ArgNum, C.blockCount());
+  SVal ArgE = getIteratorArg(Call, ArgNum + 1, C.blockCount());
+
+  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+  if (!CE)
+    return false;
 
-  return false;
+  const FnCheck *Handler = Callbacks.lookup(Call);
+  if (!Handler)
+    return false;
+
+  (this->**Handler)(C, CE, ArgB, ArgE);
+  return true;
 }
 
-void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
-                                unsigned paramNum) const {
+void STLAlgorithmModeling::evalFind(CheckerContext &C, const CallExpr *CE,
+                                    SVal Begin, SVal End) const {
   auto State = C.getState();
   auto &SVB = C.getSValBuilder();
   const auto *LCtx = C.getLocationContext();
 
   SVal RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
-  SVal Param = State->getSVal(CE->getArg(paramNum), LCtx);
 
   auto StateFound = State->BindExpr(CE, LCtx, RetVal);
 
@@ -119,7 +113,7 @@
   // assume that in case of successful search the position of the found element
   // is not ahead of it.
   // FIXME: Reverse iterators
-  const auto *Pos = getIteratorPosition(State, Param);
+  const auto *Pos = getIteratorPosition(State, Begin);
   if (Pos) {
     StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
                                         CE, LCtx, C.blockCount());
@@ -135,13 +129,11 @@
     StateFound = StateFound->assume(GreaterOrEqual.castAs<DefinedSVal>(), true);
   }
 
-  Param = State->getSVal(CE->getArg(paramNum + 1), LCtx);
-
   // If we have an iterator position for the range-end argument then we can
   // assume that in case of successful search the position of the found element
   // is ahead of it.
   // FIXME: Reverse iterators
-  Pos = getIteratorPosition(State, Param);
+  Pos = getIteratorPosition(State, End);
   if (Pos) {
     StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
                                         CE, LCtx, C.blockCount());
@@ -160,7 +152,7 @@
   C.addTransition(StateFound);
 
   if (AggressiveStdFindModeling) {
-    auto StateNotFound = State->BindExpr(CE, LCtx, Param);
+    auto StateNotFound = State->BindExpr(CE, LCtx, End);
     C.addTransition(StateNotFound);
   }
 }
Index: clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
@@ -32,16 +32,12 @@
 
   std::unique_ptr<BugType> MismatchedBugType;
 
-  void verifyMatch(CheckerContext &C, const SVal &Iter,
-                   const MemRegion *Cont) const;
-  void verifyMatch(CheckerContext &C, const SVal &Iter1,
-                   const SVal &Iter2) const;
-  void reportBug(const StringRef &Message, const SVal &Val1,
-                 const SVal &Val2, CheckerContext &C,
-                 ExplodedNode *ErrNode) const;
-  void reportBug(const StringRef &Message, const SVal &Val,
-                 const MemRegion *Reg, CheckerContext &C,
-                 ExplodedNode *ErrNode) const;
+  void verifyMatch(CheckerContext &C, SVal Iter, const MemRegion *Cont) const;
+  void verifyMatch(CheckerContext &C, SVal Iter1, SVal Iter2) const;
+  void reportBug(const StringRef &Message, SVal Val1, SVal Val2,
+                 CheckerContext &C, ExplodedNode *ErrNode) const;
+  void reportBug(const StringRef &Message, SVal Val, const MemRegion *Reg,
+                 CheckerContext &C, ExplodedNode *ErrNode) const;
 
 public:
   MismatchedIteratorChecker();
@@ -66,51 +62,55 @@
   if (!Func)
     return;
 
+  // If the call has no arguments, there is nothing to check here
+  if (Call.getNumArgs() < 1)
+    return;
+
   if (Func->isOverloadedOperator() &&
       isComparisonOperator(Func->getOverloadedOperator())) {
     // Check for comparisons of iterators of different containers
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-      if (Call.getNumArgs() < 1)
-        return;
-
       if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) ||
           !isIteratorType(Call.getArgExpr(0)->getType()))
         return;
 
-      verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
+      verifyMatch(C, InstCall->getCXXThisVal(), Arg0);
     } else {
       if (Call.getNumArgs() < 2)
         return;
 
+      SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
       if (!isIteratorType(Call.getArgExpr(0)->getType()) ||
           !isIteratorType(Call.getArgExpr(1)->getType()))
         return;
 
-      verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
+      verifyMatch(C, Arg0, Arg1);
     }
   } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
     const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
     if (!ContReg)
       return;
+
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
     // Check for erase, insert and emplace using iterator of another container
     if (isEraseCall(Func) || isEraseAfterCall(Func)) {
-      verifyMatch(C, Call.getArgSVal(0),
-                  InstCall->getCXXThisVal().getAsRegion());
+      verifyMatch(C, Arg0, InstCall->getCXXThisVal().getAsRegion());
       if (Call.getNumArgs() == 2) {
-        verifyMatch(C, Call.getArgSVal(1),
-                    InstCall->getCXXThisVal().getAsRegion());
+        SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+        verifyMatch(C, Arg1, InstCall->getCXXThisVal().getAsRegion());
       }
     } else if (isInsertCall(Func)) {
-      verifyMatch(C, Call.getArgSVal(0),
-                  InstCall->getCXXThisVal().getAsRegion());
+      verifyMatch(C, Arg0, InstCall->getCXXThisVal().getAsRegion());
       if (Call.getNumArgs() == 3 &&
           isIteratorType(Call.getArgExpr(1)->getType()) &&
           isIteratorType(Call.getArgExpr(2)->getType())) {
-        verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
+        SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+        SVal Arg2 = getIteratorArg(Call, 2, C.blockCount());
+        verifyMatch(C, Arg1, Arg2);
       }
     } else if (isEmplaceCall(Func)) {
-      verifyMatch(C, Call.getArgSVal(0),
-                  InstCall->getCXXThisVal().getAsRegion());
+      verifyMatch(C, Arg0, InstCall->getCXXThisVal().getAsRegion());
     }
   } else if (isa<CXXConstructorCall>(&Call)) {
     // Check match of first-last iterator pair in a constructor of a container
@@ -129,7 +129,9 @@
         !isIteratorType(Call.getArgExpr(1)->getType()))
       return;
 
-    verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+    SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+    verifyMatch(C, Arg0, Arg1);
   } else {
     // The main purpose of iterators is to abstract away from different
     // containers and provide a (maybe limited) uniform access to them.
@@ -167,7 +169,7 @@
       if (!isIteratorType(TAType))
         continue;
 
-      SVal LHS = UndefinedVal();
+      Optional<SVal> LHS = None;
 
       // For every template parameter which is an iterator type in the
       // instantiation look for all functions' parameters' type by it and
@@ -179,10 +181,13 @@
         if (!ParamType ||
             ParamType->getReplacedParameter()->getDecl() != TPDecl)
           continue;
-        if (LHS.isUndef()) {
-          LHS = Call.getArgSVal(J);
+
+        SVal ArgJ = getIteratorArg(Call, J, C.blockCount());
+
+        if (!LHS.hasValue()) {
+          LHS = ArgJ;
         } else {
-          verifyMatch(C, LHS, Call.getArgSVal(J));
+          verifyMatch(C, *LHS, ArgJ);
         }
       }
     }
@@ -200,7 +205,7 @@
   verifyMatch(C, LVal, RVal);
 }
 
-void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
+void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, SVal Iter,
                                             const MemRegion *Cont) const {
   // Verify match between a container and the container of an iterator
   Cont = Cont->getMostDerivedObjectRegion();
@@ -231,14 +236,13 @@
     if (!N) {
       return;
     }
-    reportBug("Container accessed using foreign iterator argument.",
-                        Iter, Cont, C, N);
+    reportBug("Container accessed using foreign iterator argument.", Iter, Cont,
+              C, N);
   }
 }
 
-void MismatchedIteratorChecker::verifyMatch(CheckerContext &C,
-                                            const SVal &Iter1,
-                                            const SVal &Iter2) const {
+void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, SVal Iter1,
+                                            SVal Iter2) const {
   // Verify match between the containers of two iterators
   auto State = C.getState();
   const auto *Pos1 = getIteratorPosition(State, Iter1);
@@ -275,10 +279,8 @@
   }
 }
 
-void MismatchedIteratorChecker::reportBug(const StringRef &Message,
-                                          const SVal &Val1,
-                                          const SVal &Val2,
-                                          CheckerContext &C,
+void MismatchedIteratorChecker::reportBug(const StringRef &Message, SVal Val1,
+                                          SVal Val2, CheckerContext &C,
                                           ExplodedNode *ErrNode) const {
   auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
                                                     ErrNode);
@@ -287,8 +289,8 @@
   C.emitReport(std::move(R));
 }
 
-void MismatchedIteratorChecker::reportBug(const StringRef &Message,
-                                          const SVal &Val, const MemRegion *Reg,
+void MismatchedIteratorChecker::reportBug(const StringRef &Message, SVal Val,
+                                          const MemRegion *Reg,
                                           CheckerContext &C,
                                           ExplodedNode *ErrNode) const {
   auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
Index: clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
@@ -89,18 +89,14 @@
       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
         verifyIncrement(C, InstCall->getCXXThisVal());
       } else {
-        if (Call.getNumArgs() >= 1) {
-          verifyIncrement(C, Call.getArgSVal(0));
-        }
+        verifyIncrement(C, getIteratorArg(Call, 0, C.blockCount()));
       }
     } else if (isDecrementOperator(Func->getOverloadedOperator())) {
       // Check for out-of-range decrementions
       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
         verifyDecrement(C, InstCall->getCXXThisVal());
       } else {
-        if (Call.getNumArgs() >= 1) {
-          verifyDecrement(C, Call.getArgSVal(0));
-        }
+        verifyDecrement(C, getIteratorArg(Call, 0, C.blockCount()));
       }
     } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
@@ -115,7 +111,8 @@
         if (Call.getNumArgs() >= 2 &&
             Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
           verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
-                                 Call.getArgSVal(0), Call.getArgSVal(1));
+                                 getIteratorArg(Call, 0, C.blockCount()),
+                                 Call.getArgSVal(1));
         }
       }
     } else if (isDereferenceOperator(Func->getOverloadedOperator())) {
@@ -123,18 +120,20 @@
       if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
         verifyDereference(C, InstCall->getCXXThisVal());
       } else {
-        verifyDereference(C, Call.getArgSVal(0));
+        verifyDereference(C, getIteratorArg(Call, 0, C.blockCount()));
       }
     }
   } else {
     const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call);
     if (Verifier) {
+      SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+
       if (Call.getNumArgs() > 1) {
-        (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1));
+        (this->**Verifier)(C, Arg0, Call.getArgSVal(1));
       } else {
         auto &BVF = C.getSValBuilder().getBasicValueFactory();
         (this->**Verifier)(
-            C, Call.getArgSVal(0),
+            C, Arg0,
             nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
       }
     }
Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -84,9 +84,8 @@
 
 class IteratorModeling
     : public Checker<check::PostCall, check::PostStmt<UnaryOperator>,
-                     check::PostStmt<BinaryOperator>,
-                     check::PostStmt<MaterializeTemporaryExpr>,
-                     check::Bind, check::LiveSymbols, check::DeadSymbols> {
+                     check::PostStmt<BinaryOperator>, check::Bind,
+                     check::LiveSymbols, check::DeadSymbols> {
 
   using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *,
                                                SVal, SVal, SVal) const;
@@ -98,27 +97,26 @@
                                  const AdvanceFn *Handler) const;
 
   void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
-                        const SVal &LVal, const SVal &RVal,
-                        OverloadedOperatorKind Op) const;
+                        SVal LVal, SVal RVal, OverloadedOperatorKind Op) const;
   void processComparison(CheckerContext &C, ProgramStateRef State,
-                         SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal,
+                         SymbolRef Sym1, SymbolRef Sym2, SVal RetVal,
                          OverloadedOperatorKind Op) const;
-  void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
-                       bool Postfix) const;
-  void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
-                       bool Postfix) const;
+  void handleIncrement(CheckerContext &C, SVal RetVal,
+                       SVal Iter, bool Postfix) const;
+  void handleDecrement(CheckerContext &C, SVal RetVal,
+                       SVal Iter, bool Postfix) const;
   void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
-                              OverloadedOperatorKind Op, const SVal &RetVal,
-                              const SVal &Iterator, const SVal &Amount) const;
+                              OverloadedOperatorKind Op, SVal RetVal,
+                              SVal Iterator, SVal Amount) const;
   void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator,
                            OverloadedOperatorKind OK, SVal Offset) const;
-  void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
-                     SVal Amount) const;
-  void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
-                  SVal Amount) const;
-  void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
-                  SVal Amount) const;
-  void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
+  void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal,
+                     SVal Iter, SVal Amount) const;
+  void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal,
+                  SVal Iter, SVal Amount) const;
+  void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal,
+                  SVal Iter, SVal Amount) const;
+  void assignToContainer(CheckerContext &C, const Expr *CE, SVal RetVal,
                          const MemRegion *Cont) const;
   bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const;
   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
@@ -152,19 +150,13 @@
   void checkPostStmt(const BinaryOperator *BO, 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;
 };
 
 bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
 bool isSimpleComparisonOperator(BinaryOperatorKind OK);
-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);
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, SVal Val);
 const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call);
 
 } // namespace
@@ -198,15 +190,17 @@
   auto State = C.getState();
 
   // Already bound to container?
-  if (getIteratorPosition(State, Call.getReturnValue()))
+  SVal RetVal = getReturnIterator(Call);
+  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);
+    SVal Arg = getIteratorArg(Call, 0, C.blockCount());
+    if (const auto *Pos = getIteratorPosition(State, Arg)) {
+      State = setIteratorPosition(State, RetVal, *Pos);
       if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
-        State = removeIteratorPosition(State, Call.getArgSVal(0));
+        State = removeIteratorPosition(State, Arg);
       }
       C.addTransition(State);
       return;
@@ -224,8 +218,7 @@
             C.getASTContext()).getTypePtr() ==
         Call.getResultType().getDesugaredType(C.getASTContext()).getTypePtr()) {
       if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
-        assignToContainer(C, OrigExpr, Call.getReturnValue(),
-                          Pos->getContainer());
+        assignToContainer(C, OrigExpr, RetVal, Pos->getContainer());
         return;
       }
     }
@@ -235,6 +228,9 @@
 void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S,
                                  CheckerContext &C) const {
   auto State = C.getState();
+  if (Val.getAs<nonloc::LazyCompoundVal>())
+    return;
+
   const auto *Pos = getIteratorPosition(State, Val);
   if (Pos) {
     State = setIteratorPosition(State, Loc, *Pos);
@@ -289,17 +285,6 @@
   }
 }
 
-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 {
   // Keep symbolic expressions of iterator positions alive
@@ -307,8 +292,9 @@
   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)) {
         SR.markLive(*i);
+      }
   }
 
   auto SymbolMap = State->get<IteratorSymbolMap>();
@@ -329,12 +315,7 @@
   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);
-      }
+      State = State->remove<IteratorRegionMap>(Reg.first);
     }
   }
 
@@ -352,74 +333,82 @@
 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;
-      }
+  if (isSimpleComparisonOperator(Op)) {
+    const auto *OrigExpr = Call.getOriginExpr();
+    if (!OrigExpr)
+      return;
 
-      handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
-                         Call.getArgSVal(1), Op);
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleComparison(C, OrigExpr, Call.getReturnValue(),
+                       InstCall->getCXXThisVal(), Arg0, Op);
       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) {
-        const Expr *FirstArg = Call.getArgExpr(0);
-        const Expr *SecondArg = Call.getArgExpr(1);
-        const QualType FirstType = FirstArg->getType();
-        const QualType SecondType = SecondArg->getType();
-
-        if (FirstType->isIntegralOrEnumerationType() ||
-            SecondType->isIntegralOrEnumerationType()) {
-          // In case of operator+ the iterator can be either on the LHS (eg.:
-          // it + 1), or on the RHS (eg.: 1 + it). Both cases are modeled.
-          const bool IsIterFirst = FirstType->isStructureOrClassType();
-          const SVal FirstArg = Call.getArgSVal(0);
-          const SVal SecondArg = Call.getArgSVal(1);
-          const SVal &Iterator = IsIterFirst ? FirstArg : SecondArg;
-          const SVal &Amount = IsIterFirst ? SecondArg : FirstArg;
-
-          handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
-                                 Iterator, Amount);
-          return;
-        }
+    SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+    handleComparison(C, OrigExpr, Call.getReturnValue(), Arg0, Arg1, 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, getReturnIterator(Call),
+                               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) {
+      const Expr *FirstArg = Call.getArgExpr(0);
+      const Expr *SecondArg = Call.getArgExpr(1);
+      const QualType FirstType = FirstArg->getType();
+      const QualType SecondType = SecondArg->getType();
+
+      if (FirstType->isIntegralOrEnumerationType() ||
+          SecondType->isIntegralOrEnumerationType()) {
+        // In case of operator+ the iterator can be either on the LHS (eg.:
+        // it + 1), or on the RHS (eg.: 1 + it). Both cases are modeled.
+        const bool IsIterFirst = FirstType->isStructureOrClassType();
+        const SVal Iterator = getIteratorArg(Call, IsIterFirst ? 0 : 1,
+                                             C.blockCount());
+        const SVal Amount = Call.getArgSVal(IsIterFirst ? 1 : 0);
+        
+        handleRandomIncrOrDecr(C, OrigExpr, Op, getReturnIterator(Call),
+                               Iterator, Amount);
         return;
       }
-
-      handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
-                      Call.getNumArgs());
-      return;
-    } else if (isDecrementOperator(Op)) {
-      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-        handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
-                        Call.getNumArgs());
+    } else {
+      if (Call.getNumArgs() >= 2 &&
+          Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
+        SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+        handleRandomIncrOrDecr(C, OrigExpr, Op, getReturnIterator(Call), Arg0,
+                               Call.getArgSVal(1));
         return;
       }
+    }
+  } else if (isIncrementOperator(Op)) {
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleIncrement(C, getReturnIterator(Call), InstCall->getCXXThisVal(),
+                      Call.getNumArgs());
+      return;
+    }
 
-      handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
-                        Call.getNumArgs());
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+    handleIncrement(C, getReturnIterator(Call), Arg0, Call.getNumArgs());
+    return;
+  } else if (isDecrementOperator(Op)) {
+    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+      handleDecrement(C, getReturnIterator(Call), InstCall->getCXXThisVal(),
+                      Call.getNumArgs());
       return;
     }
+
+    SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+    handleDecrement(C, getReturnIterator(Call), Arg0, Call.getNumArgs());
+    return;
+  }
 }
 
 void
@@ -427,9 +416,10 @@
                                             const CallEvent &Call,
                                             const Expr *OrigExpr,
                                             const AdvanceFn *Handler) const {
-  if (!C.wasInlined) {
-    (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
-                      Call.getArgSVal(0), Call.getArgSVal(1));
+  SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+   if (!C.wasInlined) {
+     (this->**Handler)(C, OrigExpr, getReturnIterator(Call), Arg0,
+                       Call.getArgSVal(1));
     return;
   }
 
@@ -438,23 +428,22 @@
   const auto *IdInfo = cast<FunctionDecl>(Call.getDecl())->getIdentifier();
   if (IdInfo) {
     if (IdInfo->getName() == "advance") {
-      if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) {
-        (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
-                          Call.getArgSVal(0), Call.getArgSVal(1));
+      if (noChangeInAdvance(C, Arg0, OrigExpr)) {
+        (this->**Handler)(C, OrigExpr, getReturnIterator(Call), Arg0,
+                          Call.getArgSVal(1));
       }
     }
   }
 }
 
 void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
-                                       SVal RetVal, const SVal &LVal,
-                                       const SVal &RVal,
-                                       OverloadedOperatorKind Op) const {
+                                        SVal RetVal, SVal LVal, SVal RVal,
+                                        OverloadedOperatorKind Op) const {
   // Record the operands and the operator of the comparison for the next
   // evalAssume, if the result is a symbolic expression. If it is a concrete
   // value (only one branch is possible), then transfer the state between
   // the operands according to the operator and the result
-   auto State = C.getState();
+  auto State = C.getState();
   const auto *LPos = getIteratorPosition(State, LVal);
   const auto *RPos = getIteratorPosition(State, RVal);
   const MemRegion *Cont = nullptr;
@@ -502,41 +491,28 @@
     State = State->BindExpr(CE, LCtx, RetVal);
   }
 
-  processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
-}
+  if (const auto DefRetVal = RetVal.getAs<DefinedSVal>()) {
+    ProgramStateRef StateEqual, StateNonEqual;
+    std::tie(StateEqual, StateNonEqual) =
+      assumeComparison(State, LPos->getOffset(), RPos->getOffset(), *DefRetVal,
+                       Op);
 
-void IteratorModeling::processComparison(CheckerContext &C,
-                                         ProgramStateRef State, SymbolRef Sym1,
-                                         SymbolRef Sym2, const SVal &RetVal,
-                                         OverloadedOperatorKind Op) const {
-  if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
-    if ((State = relateSymbols(State, Sym1, Sym2,
-                              (Op == OO_EqualEqual) ==
-                               (TruthVal->getValue() != 0)))) {
-      C.addTransition(State);
-    } else {
+    if (!StateEqual && !StateNonEqual) {
       C.generateSink(State, C.getPredecessor());
+      return;
     }
-    return;
-  }
 
-  const auto ConditionVal = RetVal.getAs<DefinedSVal>();
-  if (!ConditionVal)
-    return;
+    if (StateEqual)
+      C.addTransition(StateEqual);
 
-  if (auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) {
-    StateTrue = StateTrue->assume(*ConditionVal, true);
-    C.addTransition(StateTrue);
+    if (StateNonEqual)
+      C.addTransition(StateNonEqual);
   }
 
-  if (auto StateFalse = relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual)) {
-    StateFalse = StateFalse->assume(*ConditionVal, false);
-    C.addTransition(StateFalse);
-  }
 }
 
-void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal,
-                                       const SVal &Iter, bool Postfix) const {
+void IteratorModeling::handleIncrement(CheckerContext &C, SVal RetVal,
+                                       SVal Iter, bool Postfix) const {
   // Increment the symbolic expressions which represents the position of the
   // iterator
   auto State = C.getState();
@@ -561,8 +537,8 @@
   C.addTransition(State);
 }
 
-void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal,
-                                       const SVal &Iter, bool Postfix) const {
+void IteratorModeling::handleDecrement(CheckerContext &C, SVal RetVal,
+                                       SVal Iter, bool Postfix) const {
   // Decrement the symbolic expressions which represents the position of the
   // iterator
   auto State = C.getState();
@@ -589,9 +565,8 @@
 
 void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
                                               OverloadedOperatorKind Op,
-                                              const SVal &RetVal,
-                                              const SVal &Iterator,
-                                              const SVal &Amount) const {
+                                              SVal RetVal, SVal Iterator,
+                                              SVal Amount) const {
   // Increment or decrement the symbolic expressions which represents the
   // position of the iterator
   auto State = C.getState();
@@ -616,7 +591,7 @@
   auto AdvancedState = advancePosition(State, Iterator, Op, *Value);
   if (AdvancedState) {
     const auto *NewPos = getIteratorPosition(AdvancedState, Iterator);
-    assert(NewPos &&
+   assert(NewPos &&
            "Iterator should have position after successful advancement");
 
     State = setIteratorPosition(State, TgtVal, *NewPos);
@@ -677,17 +652,19 @@
 }
 
 void IteratorModeling::handlePrev(CheckerContext &C, const Expr *CE,
-                                  SVal RetVal, SVal Iter, SVal Amount) const {
+                                  SVal RetVal, SVal Iter,
+                                  SVal Amount) const {
   handleRandomIncrOrDecr(C, CE, OO_Minus, RetVal, Iter, Amount);
 }
 
 void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE,
-                                  SVal RetVal, SVal Iter, SVal Amount) const {
+                                  SVal RetVal, SVal Iter,
+                                  SVal Amount) const {
   handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount);
 }
 
 void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
-                                         const SVal &RetVal,
+                                         SVal RetVal,
                                          const MemRegion *Cont) const {
   Cont = Cont->getMostDerivedObjectRegion();
 
@@ -775,60 +752,14 @@
   return OK == BO_EQ || OK == BO_NE;
 }
 
-ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, SVal Val) {
   if (auto Reg = Val.getAsRegion()) {
     Reg = Reg->getMostDerivedObjectRegion();
     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;
-}
-
-ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
-                              SymbolRef Sym2, bool Equal) {
-  auto &SVB = State->getStateManager().getSValBuilder();
-
-  // FIXME: This code should be reworked as follows:
-  // 1. Subtract the operands using evalBinOp().
-  // 2. Assume that the result doesn't overflow.
-  // 3. Compare the result to 0.
-  // 4. Assume the result of the comparison.
-  const auto comparison =
-    SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
-                  nonloc::SymbolVal(Sym2), SVB.getConditionType());
-
-  assert(comparison.getAs<DefinedSVal>() &&
-    "Symbol comparison must be a `DefinedSVal`");
-
-  auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
-  if (!NewState)
-    return nullptr;
-
-  if (const auto CompSym = comparison.getAsSymbol()) {
-    assert(isa<SymIntExpr>(CompSym) &&
-           "Symbol comparison must be a `SymIntExpr`");
-    assert(BinaryOperator::isComparisonOp(
-               cast<SymIntExpr>(CompSym)->getOpcode()) &&
-           "Symbol comparison must be a comparison");
-    return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
   }
-
-  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;
+  return State;
 }
 
 const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call) {
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.h
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/Iterator.h
+++ clang/lib/StaticAnalyzer/Checkers/Iterator.h
@@ -179,11 +179,30 @@
                                 const SVal &Distance);
 ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
                                  long Scale);
+
+// Returns states with comparison results assumed to `true` and `false`. If
+// only one of them is possible then the second value of the pair is `nullptr`.
+// If none is possible then both values are `nullptr`.
+std::pair<ProgramStateRef, ProgramStateRef>
+assumeComparison(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
+                 DefinedSVal RetVal, OverloadedOperatorKind Op);
+
 bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
              BinaryOperator::Opcode Opc);
 bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
              BinaryOperator::Opcode Opc);
 
+// Returns the value of the iterator argument if it non-class value (a pointer
+// or a reference). Otherwise it returns the iterator parameter location (see
+// CallEvent::getParameterLocation()).
+SVal getIteratorArg(const CallEvent &Call, unsigned Index, unsigned BlockCount);
+
+// If the call returns an class instance iterator by value then this function
+// retrieves and returns it from the construction context of the call.
+// Otherwise (for non-class types) it simply returns the return value of the
+// call.
+SVal getReturnIterator(const CallEvent &Call);
+
 } // namespace iterator
 } // namespace ento
 } // namespace clang
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
+++ clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
@@ -10,12 +10,17 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+
 #include "Iterator.h"
 
 namespace clang {
 namespace ento {
 namespace iterator {
 
+ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
+                              SymbolRef Sym2, bool Equal);
+
 bool isIteratorType(const QualType &Type) {
   if (Type->isPointerType())
     return true;
@@ -24,6 +29,28 @@
   return isIterator(CRD);
 }
 
+static bool hasOperator(const CXXRecordDecl *CRD, OverloadedOperatorKind Op,
+                        unsigned NumParams) {
+  for (const auto *Method : CRD->methods()) {
+    if (!Method->isOverloadedOperator())
+      continue;
+
+    if (Method->getOverloadedOperator() == Op &&
+        Method->getNumParams() == NumParams)
+      return true;
+  }
+
+  for (auto Base : CRD->bases()) {
+    const auto *BaseCRD =
+      Base.getType()->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
+
+    if (BaseCRD && hasOperator(BaseCRD, Op, NumParams))
+      return true;
+  }
+
+  return false;
+}
+
 bool isIterator(const CXXRecordDecl *CRD) {
   if (!CRD)
     return false;
@@ -33,39 +60,27 @@
         Name.endswith_lower("it")))
     return false;
 
-  bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
-       HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
-  for (const auto *Method : CRD->methods()) {
-    if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
-      if (Ctor->isCopyConstructor()) {
-        HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
-      }
-      continue;
-    }
-    if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
-      HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
-      continue;
-    }
-    if (Method->isCopyAssignmentOperator()) {
-      HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
-      continue;
-    }
-    if (!Method->isOverloadedOperator())
-      continue;
-    const auto OPK = Method->getOverloadedOperator();
-    if (OPK == OO_PlusPlus) {
-      HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
-      HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
-      continue;
-    }
-    if (OPK == OO_Star) {
-      HasDerefOp = (Method->getNumParams() == 0);
-      continue;
-    }
-  }
+  if ((!CRD->hasSimpleCopyConstructor() &&
+       !CRD->hasUserDeclaredCopyConstructor()) || 
+      (!CRD->hasSimpleCopyAssignment() &&
+       !CRD->hasUserDeclaredCopyAssignment()) ||
+      (!CRD->hasSimpleDestructor() &&
+       !CRD->hasUserDeclaredDestructor()))
+    return false;
+
+  // Operator Prefix ++
+  if (!hasOperator(CRD, OO_PlusPlus, 0))
+    return false;
+
+  // Operator Postfix ++
+  if (!hasOperator(CRD, OO_PlusPlus, 1))
+    return false;
+
+  // Operator *
+  if (!hasOperator(CRD, OO_Star, 0))
+    return false;
 
-  return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
-         HasPostIncrOp && HasDerefOp;
+  return true;
 }
 
 bool isComparisonOperator(OverloadedOperatorKind OK) {
@@ -188,8 +203,6 @@
     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;
 }
@@ -201,10 +214,8 @@
     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;
+  return State;
 }
 
 ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
@@ -296,6 +307,62 @@
   return NewState;
 }
 
+std::pair<ProgramStateRef, ProgramStateRef>
+assumeComparison(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
+                 DefinedSVal RetVal, OverloadedOperatorKind Op) {
+  assert(CXXOperatorCallExpr::isComparisonOp(Op) &&
+         "`Op` must be a comparison operator");
+  if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
+    State = relateSymbols(State, Sym1, Sym2,
+                          (Op == OO_EqualEqual) == TruthVal->getValue());
+    return std::make_pair(State, nullptr);
+  }
+
+  ProgramStateRef StateTrue =
+    relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual);
+  ProgramStateRef StateFalse =
+    relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual);
+
+  if (StateTrue)
+    StateTrue = StateTrue->assume(RetVal, true);
+  if (StateFalse)
+    StateFalse = StateFalse->assume(RetVal, false);
+
+  return std::make_pair(StateTrue, StateFalse);
+}
+
+ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
+                              SymbolRef Sym2, bool Equal) {
+  auto &SVB = State->getStateManager().getSValBuilder();
+
+  // FIXME: This code should be reworked as follows:
+  // 1. Subtract the operands using evalBinOp().
+  // 2. Assume that the result doesn't overflow.
+  // 3. Compare the result to 0.
+  // 4. Assume the result of the comparison.
+  const auto comparison =
+    SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
+                  nonloc::SymbolVal(Sym2), SVB.getConditionType());
+
+  assert(comparison.getAs<DefinedSVal>() &&
+    "Symbol comparison must be a `DefinedSVal`");
+
+  auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
+  if (!NewState)
+    return nullptr;
+
+  if (const auto CompSym = comparison.getAsSymbol()) {
+    assert(isa<SymIntExpr>(CompSym) &&
+           "Symbol comparison must be a `SymIntExpr`");
+    assert(BinaryOperator::isComparisonOp(
+               cast<SymIntExpr>(CompSym)->getOpcode()) &&
+           "Symbol comparison must be a comparison");
+    return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
+  }
+
+  return NewState;
+}
+
 bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
              BinaryOperator::Opcode Opc) {
   return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
@@ -314,6 +381,29 @@
   return !State->assume(comparison.castAs<DefinedSVal>(), false);
 }
 
+SVal getIteratorArg(const CallEvent& Call, unsigned Index,
+                    unsigned BlockCount) {
+  SVal Arg = Call.getArgSVal(Index);
+  const Expr *ArgExpr = Call.getArgExpr(Index);
+
+  if (ArgExpr->getValueKind() != VK_RValue)
+    return Arg;
+
+  if (!ArgExpr->getType().getDesugaredType(
+          Call.getState()->getStateManager().getContext())->isRecordType())
+    return Arg;
+
+  return loc::MemRegionVal(Call.getParameterLocation(Index, BlockCount));
+}
+
+SVal getReturnIterator(const CallEvent &Call) {
+  Optional<SVal> RetValUnderConstr = Call.getReturnValueUnderConstruction();
+  if (RetValUnderConstr.hasValue())
+    return *RetValUnderConstr;
+
+  return Call.getReturnValue();
+}
+
 } // namespace iterator
 } // namespace ento
 } // namespace clang
Index: clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
@@ -33,9 +33,9 @@
 
   std::unique_ptr<BugType> InvalidatedBugType;
 
-  void verifyAccess(CheckerContext &C, const SVal &Val) const;
-  void reportBug(const StringRef &Message, const SVal &Val,
-                 CheckerContext &C, ExplodedNode *ErrNode) const;
+  void verifyAccess(CheckerContext &C, SVal Val) const;
+  void reportBug(const StringRef &Message, SVal Val, CheckerContext &C,
+                 ExplodedNode *ErrNode) const;
 public:
   InvalidatedIteratorChecker();
 
@@ -67,7 +67,8 @@
     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
       verifyAccess(C, InstCall->getCXXThisVal());
     } else {
-      verifyAccess(C, Call.getArgSVal(0));
+      SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+      verifyAccess(C, Arg0);
     }
   }
 }
@@ -114,7 +115,8 @@
   verifyAccess(C, BaseVal);
 }
 
-void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
+void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C,
+                                              SVal Val) const {
   auto State = C.getState();
   const auto *Pos = getIteratorPosition(State, Val);
   if (Pos && !Pos->isValid()) {
@@ -127,7 +129,7 @@
 }
 
 void InvalidatedIteratorChecker::reportBug(const StringRef &Message,
-                                           const SVal &Val, CheckerContext &C,
+                                           SVal Val, CheckerContext &C,
                                            ExplodedNode *ErrNode) const {
   auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
                                                     Message, ErrNode);
Index: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -32,24 +32,44 @@
 class ContainerModeling
   : public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
 
-  void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal,
-                   SVal Cont) const;
-  void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal,
-                 SVal Cont) const;
-  void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr,
-                        SVal OldCont = UndefinedVal()) const;
-  void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const;
-  void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const;
-  void handlePushBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
-  void handlePopBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
-  void handlePushFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
-  void handlePopFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
-  void handleInsert(CheckerContext &C, SVal Cont, SVal Iter) const;
-  void handleErase(CheckerContext &C, SVal Cont, SVal Iter) const;
-  void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2) const;
-  void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter) const;
-  void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1,
-                        SVal Iter2) const;
+  void handleAssignment(CheckerContext &C, const Expr *CE, SVal Cont,
+                        Optional<SVal> = None) const;
+
+  // Handler functions for different container operations.
+  // SVal Parameters:
+  // - Cont:                      The affected container (*this)
+  // - RetVal:                    Return value of the operation
+  // - Iter (or Iter1 and Iter2): Iterator parameters
+
+  void handleBegin(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                   SVal Cont, SVal RetVal) const;
+  void handleEnd(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                 SVal Cont, SVal RetVal) const;
+  void handleEmpty(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                   SVal Cont, SVal RetVal) const;
+  void handleAssign(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                    SVal Cont, SVal RetVal) const;
+  void handleClear(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                   SVal Cont, SVal RetVal) const;
+  void handlePushBack(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                      SVal Cont, SVal RetVal) const;
+  void handlePopBack(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                     SVal Cont, SVal RetVal) const;
+  void handlePushFront(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                       SVal Cont, SVal RetVal) const;
+  void handlePopFront(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                      SVal Cont, SVal RetVal) const;
+  void handleInsert(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                    SVal Cont, SVal Iter, SVal RetVal) const;
+  void handleErase(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                   SVal Cont, SVal Iter, SVal RetVal) const;
+  void handleErase(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                   SVal Cont, SVal Iter1, SVal Iter2, SVal RetVal) const;
+  void handleEraseAfter(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                        SVal Cont, SVal Iter, SVal RetVal) const;
+  void handleEraseAfter(CheckerContext &C, const Expr *CE, const Expr *ContE,
+                        SVal Cont, SVal Iter1, SVal Iter2, SVal RetVal) const;
+
   const NoteTag *getChangeTag(CheckerContext &C, StringRef Text,
                               const MemRegion *ContReg,
                               const Expr *ContE) const;
@@ -63,54 +83,50 @@
   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
 
-  using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
-                                                  const Expr *) const;
-  using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
-                                                   SVal) const;
-  using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal,
-                                                   SVal) const;
-
-  CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
-    {{0, "clear", 0},
-     &ContainerModeling::handleClear},
-    {{0, "assign", 2},
-     &ContainerModeling::handleAssign},
-    {{0, "push_back", 1},
-     &ContainerModeling::handlePushBack},
-    {{0, "emplace_back", 1},
-     &ContainerModeling::handlePushBack},
-    {{0, "pop_back", 0},
-     &ContainerModeling::handlePopBack},
-    {{0, "push_front", 1},
-     &ContainerModeling::handlePushFront},
-    {{0, "emplace_front", 1},
-     &ContainerModeling::handlePushFront},
-    {{0, "pop_front", 0},
-     &ContainerModeling::handlePopFront},
+  using ZeroItParamFn =
+    void (ContainerModeling::*)(CheckerContext &, const Expr *, const Expr *,
+                                SVal, SVal) const;
+  using OneItParamFn =
+    void (ContainerModeling::*)(CheckerContext &, const Expr *, const Expr *,
+                                SVal, SVal, SVal) const;
+  using TwoItParamFn =
+    void (ContainerModeling::*)(CheckerContext &, const Expr *, const Expr *,
+                                SVal, SVal, SVal, SVal) const;
+
+  CallDescriptionMap<ZeroItParamFn> ZeroIterParamFunctions = {
+    // Iterators
+    {{0, "cbegin", 0}, &ContainerModeling::handleBegin},
+    {{0, "cend", 0}, &ContainerModeling::handleEnd},
+    {{0, "begin", 0}, &ContainerModeling::handleBegin},
+    {{0, "end", 0}, &ContainerModeling::handleEnd},
+
+    // Capacity
+    {{0, "empty", 0}, &ContainerModeling::handleEmpty},
+
+    // Modifiers
+    {{0, "clear", 0}, &ContainerModeling::handleClear},
+    {{0, "assign", 2}, &ContainerModeling::handleAssign},
+    {{0, "push_back", 1}, &ContainerModeling::handlePushBack},
+    {{0, "emplace_back", 1}, &ContainerModeling::handlePushBack},
+    {{0, "pop_back", 0}, &ContainerModeling::handlePopBack},
+    {{0, "push_front", 1}, &ContainerModeling::handlePushFront},
+    {{0, "emplace_front", 1}, &ContainerModeling::handlePushFront},
+    {{0, "pop_front", 0}, &ContainerModeling::handlePopFront},
   };
                                                           
   CallDescriptionMap<OneItParamFn> OneIterParamFunctions = {
-    {{0, "insert", 2},
-     &ContainerModeling::handleInsert},
-    {{0, "emplace", 2},
-     &ContainerModeling::handleInsert},
-    {{0, "erase", 1},
-     &ContainerModeling::handleErase},
-    {{0, "erase_after", 1},
-     &ContainerModeling::handleEraseAfter},
+    {{0, "insert", 2}, &ContainerModeling::handleInsert},
+    {{0, "emplace", 2}, &ContainerModeling::handleInsert},
+    {{0, "erase", 1}, &ContainerModeling::handleErase},
+    {{0, "erase_after", 1}, &ContainerModeling::handleEraseAfter},
   };
                                                           
   CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = {
-    {{0, "erase", 2},
-     &ContainerModeling::handleErase},
-    {{0, "erase_after", 2},
-     &ContainerModeling::handleEraseAfter},
+    {{0, "erase", 2}, &ContainerModeling::handleErase},
+    {{0, "erase_after", 2}, &ContainerModeling::handleEraseAfter},
   };
-                                                          
 };
 
-bool isBeginCall(const FunctionDecl *Func);
-bool isEndCall(const FunctionDecl *Func);
 bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg);
 bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
 bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
@@ -169,51 +185,45 @@
       // Overloaded 'operator=' must be a non-static member function.
       const auto *InstCall = cast<CXXInstanceCall>(&Call);
       if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
-        handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
-                     Call.getArgSVal(0));
+        handleAssignment(C, Call.getOriginExpr(), InstCall->getCXXThisVal(),
+                         Call.getArgSVal(0));
         return;
       }
 
-      handleAssignment(C, InstCall->getCXXThisVal());
+      handleAssignment(C, Call.getOriginExpr(), InstCall->getCXXThisVal());
       return;
     }
-  } else {
-    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
-      const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
-      if (Handler0) {
-        (this->**Handler0)(C, InstCall->getCXXThisVal(),
-                           InstCall->getCXXThisExpr());
-        return;
-      }
-
-      const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call);
-      if (Handler1) {
-        (this->**Handler1)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
-        return;
-      }
+  } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+    const auto *OrigExpr = Call.getOriginExpr();
+    if (!OrigExpr)
+      return;
 
-      const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call);
-      if (Handler2) {
-        (this->**Handler2)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0),
-                           Call.getArgSVal(1));
-        return;
-      }
+    SVal RetVal = Call.getReturnValue();
+    if (isIteratorType(Call.getResultType()))
+      RetVal = getReturnIterator(Call);
 
-      const auto *OrigExpr = Call.getOriginExpr();
-      if (!OrigExpr)
-        return;
+    const ZeroItParamFn *Handler0 = ZeroIterParamFunctions.lookup(Call);
+    if (Handler0) {
+      (this->**Handler0)(C, OrigExpr, InstCall->getCXXThisExpr(),
+                         InstCall->getCXXThisVal(), RetVal);
+      return;
+    }
 
-      if (isBeginCall(Func)) {
-        handleBegin(C, OrigExpr, Call.getReturnValue(),
-                    InstCall->getCXXThisVal());
-        return;
-      }
+    const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call);
+    if (Handler1) {
+      SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+      (this->**Handler1)(C, OrigExpr, InstCall->getCXXThisExpr(),
+                         InstCall->getCXXThisVal(), Arg0, RetVal);
+      return;
+    }
 
-      if (isEndCall(Func)) {
-        handleEnd(C, OrigExpr, Call.getReturnValue(),
-                  InstCall->getCXXThisVal());
-        return;
-      }
+    const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call);
+    if (Handler2) {
+      SVal Arg0 = getIteratorArg(Call, 0, C.blockCount());
+      SVal Arg1 = getIteratorArg(Call, 1, C.blockCount());
+      (this->**Handler2)(C, OrigExpr, InstCall->getCXXThisExpr(),
+                         InstCall->getCXXThisVal(), Arg0, Arg1, RetVal);
+      return;
     }
   }
 }
@@ -257,7 +267,8 @@
 }
 
 void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
-                                   SVal RetVal, SVal Cont) const {
+                                    const Expr *, SVal Cont,
+                                    SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -273,13 +284,14 @@
                                  C.getLocationContext(), C.blockCount());
     BeginSym = getContainerBegin(State, ContReg);
   }
+
   State = setIteratorPosition(State, RetVal,
                               IteratorPosition::getPosition(ContReg, BeginSym));
   C.addTransition(State);
 }
 
 void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
-                                 SVal RetVal, SVal Cont) const {
+                                  const Expr *, SVal Cont, SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -295,13 +307,15 @@
                                C.getLocationContext(), C.blockCount());
     EndSym = getContainerEnd(State, ContReg);
   }
+
   State = setIteratorPosition(State, RetVal,
                               IteratorPosition::getPosition(ContReg, EndSym));
   C.addTransition(State);
 }
 
-void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
-                                         const Expr *CE, SVal OldCont) const {
+void ContainerModeling::handleAssignment(CheckerContext &C, const Expr *CE,
+                                         SVal Cont,
+                                         Optional<SVal> OldCont) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -318,8 +332,8 @@
 
   // In case of move, iterators of the old container (except the past-end
   // iterators) remain valid but refer to the new container
-  if (!OldCont.isUndef()) {
-    const auto *OldContReg = OldCont.getAsRegion();
+  if (OldCont.hasValue()) {
+    const auto *OldContReg = OldCont->getAsRegion();
     if (OldContReg) {
       OldContReg = OldContReg->getMostDerivedObjectRegion();
       const auto OldCData = getContainerData(State, OldContReg);
@@ -376,8 +390,65 @@
   C.addTransition(State);
 }
 
-void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont,
-                                     const Expr *ContE) const {
+void ContainerModeling::handleEmpty(CheckerContext &C, const Expr *CE,
+                                    const Expr *, SVal Cont,
+                                    SVal RetVal) const {
+  const auto *ContReg = Cont.getAsRegion();
+  if (!ContReg)
+    return;
+
+  ContReg = ContReg->getMostDerivedObjectRegion();
+
+  // If the container already has a begin symbol then use it. Otherwise first
+  // create a new one.
+  auto State = C.getState();
+  auto *LCtx = C.getLocationContext();
+
+  auto BeginSym = getContainerBegin(State, ContReg);
+  if (!BeginSym) {
+    State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
+                                 LCtx, C.blockCount());
+    BeginSym = getContainerBegin(State, ContReg);
+  }
+  auto EndSym = getContainerEnd(State, ContReg);
+  if (!EndSym) {
+    State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
+                               LCtx, C.blockCount());
+    EndSym = getContainerEnd(State, ContReg);
+  }
+
+  // We cannot make assumpotions on `UnknownVal`. Let us conjure a symbol
+  // instead.
+  if (RetVal.isUnknown()) {
+    auto &SymMgr = C.getSymbolManager();
+    RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
+        CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
+    State = State->BindExpr(CE, LCtx, RetVal);
+  }
+
+  if (const auto DefRetVal = RetVal.getAs<DefinedSVal>()) {
+    ProgramStateRef StateEmpty, StateNonEmpty;
+    std::tie(StateEmpty, StateNonEmpty) =
+      assumeComparison(State, BeginSym, EndSym, *DefRetVal, OO_EqualEqual);
+
+    if (!StateEmpty && !StateNonEmpty) {
+      // The return value of the `empty()` call contradicts the emptyness of
+      // the container.
+      C.generateSink(State, C.getPredecessor());
+      return;
+    }
+
+    if (StateEmpty)
+      C.addTransition(StateEmpty);
+
+    if (StateNonEmpty)
+      C.addTransition(StateNonEmpty);
+  }
+}
+
+void ContainerModeling::handleAssign(CheckerContext &C, const Expr *CE,
+                                     const Expr *, SVal Cont,
+                                     SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -390,8 +461,9 @@
   C.addTransition(State);
 }
 
-void ContainerModeling::handleClear(CheckerContext &C, SVal Cont,
-                                    const Expr *ContE) const {
+void ContainerModeling::handleClear(CheckerContext &C, const Expr *CE,
+                                    const Expr *ContE, SVal Cont,
+                                    SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -419,8 +491,9 @@
   C.addTransition(State, ChangeTag);
 }
 
-void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont,
-                                       const Expr *ContE) const {
+void ContainerModeling::handlePushBack(CheckerContext &C, const Expr *CE,
+                                       const Expr *ContE, SVal Cont,
+                                       SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -459,8 +532,9 @@
   }
 }
 
-void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont,
-                                      const Expr *ContE) const {
+void ContainerModeling::handlePopBack(CheckerContext &C, const Expr *CE,
+                                      const Expr *ContE, SVal Cont,
+                                      SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -499,8 +573,9 @@
   }
 }
 
-void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont,
-                                        const Expr *ContE) const {
+void ContainerModeling::handlePushFront(CheckerContext &C, const Expr *CE,
+                                        const Expr *ContE, SVal Cont,
+                                        SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -534,8 +609,9 @@
   }
 }
 
-void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont,
-                                       const Expr *ContE) const {
+void ContainerModeling::handlePopFront(CheckerContext &C, const Expr *CE,
+                                       const Expr *ContE, SVal Cont,
+                                       SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -570,8 +646,9 @@
   }
 }
 
-void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont,
-                                     SVal Iter) const {
+void ContainerModeling::handleInsert(CheckerContext &C, const Expr *CE,
+                                     const Expr *, SVal Cont, SVal Iter,
+                                     SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -601,8 +678,9 @@
   }
 }
 
-void ContainerModeling::handleErase(CheckerContext &C, SVal Cont,
-                                    SVal Iter) const {
+void ContainerModeling::handleErase(CheckerContext &C, const Expr *CE,
+                                    const Expr *, SVal Cont, SVal Iter,
+                                    SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -635,8 +713,9 @@
   C.addTransition(State);
 }
 
-void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1,
-                                    SVal Iter2) const {
+void ContainerModeling::handleErase(CheckerContext &C, const Expr *CE,
+                                    const Expr *, SVal Cont, SVal Iter1,
+                                    SVal Iter2, SVal RetVal) const {
   const auto *ContReg = Cont.getAsRegion();
   if (!ContReg)
     return;
@@ -671,8 +750,9 @@
   C.addTransition(State);
 }
 
-void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
-                                        SVal Iter) const {
+void ContainerModeling::handleEraseAfter(CheckerContext &C, const Expr *CE,
+                                         const Expr *, SVal Cont, SVal Iter,
+                                         SVal RetVal) const {
   auto State = C.getState();
   const auto *Pos = getIteratorPosition(State, Iter);
   if (!Pos)
@@ -692,8 +772,9 @@
   C.addTransition(State);
 }
 
-void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
-                                         SVal Iter1, SVal Iter2) const {
+void ContainerModeling::handleEraseAfter(CheckerContext &C, const Expr *CE,
+                                         const Expr *, SVal Cont, SVal Iter1,
+                                         SVal Iter2, SVal RetVal) const {
   auto State = C.getState();
   const auto *Pos1 = getIteratorPosition(State, Iter1);
   const auto *Pos2 = getIteratorPosition(State, Iter2);
@@ -759,20 +840,6 @@
 
 namespace {
 
-bool isBeginCall(const FunctionDecl *Func) {
-  const auto *IdInfo = Func->getIdentifier();
-  if (!IdInfo)
-    return false;
-  return IdInfo->getName().endswith_lower("begin");
-}
-
-bool isEndCall(const FunctionDecl *Func) {
-  const auto *IdInfo = Func->getIdentifier();
-  if (!IdInfo)
-    return false;
-  return IdInfo->getName().endswith_lower("end");
-}
-
 const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
                                       const MemRegion *Reg) {
   auto TI = getDynamicTypeInfo(State, Reg);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to