baloghadamsoftware updated this revision to Diff 145008.
baloghadamsoftware added a comment.
Rebased, and minor modifications done according to the comments.
https://reviews.llvm.org/D32906
Files:
lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
test/Analysis/iterator-range.cpp
test/Analysis/mismatched-iterator.cpp
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<typename Container, typename Iterator>
+bool is_cend(Container cont, Iterator it) {
+ return it == cont.cend();
+}
+
+void good_empty(std::vector<int> &v) {
+ is_cend(v, v.cbegin()); // no-warning
+}
+
+void bad_empty(std::vector<int> &v1, std::vector<int> &v2) {
+ is_cend(v1, v2.cbegin()); // expected-warning@149{{Iterator access mismatched}}
+}
+
void good_move(std::vector<int> &v1, std::vector<int> &v2) {
const auto i0 = ++v2.cbegin();
v1 = std::move(v2);
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<int> &V, int e) {
+ auto first = nonStdFind(V.begin(), V.end(), e);
+ *first; // expected-warning{{Iterator accessed outside of its range}}
+}
+
void tricky(std::vector<int> &V, int e) {
const auto first = V.begin();
const auto comp1 = (first != V.end()), comp2 = (first == V.end());
Index: lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
+++ lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
@@ -200,8 +200,8 @@
check::PreStmt<CXXConstructExpr>,
check::PreStmt<CXXOperatorCallExpr>,
check::PostStmt<MaterializeTemporaryExpr>, 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<StackFrameContext>(LCtx)->getCallSite();
+ if (!Site)
+ return;
+
+ const auto *FD = dyn_cast<FunctionDecl>(LCtx->getDecl());
+ if (!FD)
+ return;
+
+ const auto *CE = dyn_cast<CallExpr>(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 */
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits