Index: lib/StaticAnalyzer/Checkers/IteratorChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/IteratorChecker.cpp +++ lib/StaticAnalyzer/Checkers/IteratorChecker.cpp @@ -200,8 +200,8 @@ check::PreStmt, check::PreStmt, check::PostStmt, check::Bind, - check::LiveSymbols, check::DeadSymbols, - eval::Assume, eval::Call> { + check::BeginFunction, check::LiveSymbols, + check::DeadSymbols, eval::Assume, eval::Call> { mutable IdentifierInfo *II_find = nullptr, *II_find_end = nullptr, *II_find_first_of = nullptr, *II_find_if = nullptr, *II_find_if_not = nullptr, *II_lower_bound = nullptr, @@ -292,6 +292,7 @@ void checkPreStmt(const CXXConstructExpr *CCE, CheckerContext &C) const; void checkPreStmt(const CXXOperatorCallExpr *COCE, CheckerContext &C) const; void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const; + void checkBeginFunction(CheckerContext &C) const; void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const; void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const; void checkPostStmt(const MaterializeTemporaryExpr *MTE, @@ -783,6 +784,39 @@ } } +void IteratorChecker::checkBeginFunction(CheckerContext &C) const { + // Copy state of iterator arguments to iterator parameters + auto State = C.getState(); + const auto *LCtx = C.getLocationContext(); + + const auto *Site = cast(LCtx)->getCallSite(); + if (!Site) + return; + + const auto *FD = dyn_cast(LCtx->getDecl()); + if (!FD) + return; + + const auto *CE = dyn_cast(Site); + if (!CE) + return; + + bool Change = false; + int idx = 0; + for (const auto *P : FD->parameters()) { + auto Arg = State->getSVal(CE->getArg(idx++), LCtx->getParent()); + const auto *Pos = getIteratorPosition(State, Arg); + if (!Pos) + continue; + auto Param = State->getLValue(P, LCtx); + State = setIteratorPosition(State, Param, *Pos); + Change = true; + } + if (Change) { + C.addTransition(State); + } +} + void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE, CheckerContext &C) const { /* Transfer iterator state to temporary objects */ Index: test/Analysis/iterator-range.cpp =================================================================== --- test/Analysis/iterator-range.cpp +++ test/Analysis/iterator-range.cpp @@ -216,6 +216,11 @@ *first; // no-warning } +void bad_non_std_find(std::vector &V, int e) { + auto first = nonStdFind(V.begin(), V.end(), e); + *first; // expected-warning{{Iterator accessed outside of its range}} +} + void tricky(std::vector &V, int e) { const auto first = V.begin(); const auto comp1 = (first != V.end()), comp2 = (first == V.end()); Index: test/Analysis/mismatched-iterator.cpp =================================================================== --- test/Analysis/mismatched-iterator.cpp +++ test/Analysis/mismatched-iterator.cpp @@ -144,6 +144,19 @@ v1.insert(i, n); // expected-warning{{Iterator access mismatched}} } +template +bool is_cend(Container cont, Iterator it) { + return it == cont.cend(); +} + +void good_empty(std::vector &v) { + is_cend(v, v.cbegin()); // no-warning +} + +void bad_empty(std::vector &v1, std::vector &v2) { + is_cend(v1, v2.cbegin()); // expected-warning@149{{Iterator access mismatched}} +} + void good_move(std::vector &v1, std::vector &v2) { const auto i0 = ++v2.cbegin(); v1 = std::move(v2);