| // RUN: %clang --analyze -Xclang -analyzer-checker=core,experimental.cplusplus.Iterators -Xclang -verify %s |
| // XFAIL: win32 |
| |
| // FIXME: Does not work with inlined C++ methods. |
| // XFAIL: * |
| |
| #include <vector> |
| |
| void fum(std::vector<int>::iterator t); |
| |
| void foo1() |
| { |
| // iterators that are defined but not initialized |
| std::vector<int>::iterator it2; |
| fum(it2); // expected-warning{{Use of iterator that is not defined}} |
| *it2; // expected-warning{{Use of iterator that is not defined}} |
| |
| std::vector<int> v, vv; |
| std::vector<int>::iterator it = v.begin(); |
| fum(it); // no-warning |
| *it; // no-warning |
| // a valid iterator plus an integer is still valid |
| std::vector<int>::iterator et = it + 3; |
| while(it != et) { // no-warning |
| if (*it == 0) // no-warning |
| *it = 1; // no-warning |
| } |
| // iterators from different instances Cannot be compared |
| et = vv.end(); |
| while(it != et) // expected-warning{{Cannot compare iterators from different containers}} |
| ; |
| |
| for( std::vector<int>::iterator it = v.begin(); it != v.end(); it++ ) { // no-warning |
| if (*it == 1) // no-warning |
| *it = 0; // no-warning |
| } |
| |
| // copying a valid iterator results in a valid iterator |
| et = it; // no-warning |
| *et; // no-warning |
| |
| // any combo of valid iterator plus a constant is still valid |
| et = it + 2; // no-warning |
| *et; // no-warning |
| et = 2 + it; // no-warning |
| *et; // no-warning |
| et = 2 + 4 + it; // no-warning |
| *et; // no-warning |
| |
| // calling insert invalidates unless assigned to as result, but still |
| // invalidates other iterators on the same instance |
| it = v.insert( it, 1 ); // no-warning |
| *et; // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}} |
| ++it; // no-warning |
| |
| // calling erase invalidates the iterator |
| v.erase(it); // no-warning |
| et = it + 2; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} |
| et = 2 + it + 2; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} |
| et = 2 + it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} |
| ++it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} |
| it++; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} |
| *it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} |
| it = v.insert( it, 1 ); // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}} |
| // now valid after return from insert |
| *it; // no-warning |
| } |
| |
| // work with using namespace |
| void foo2() |
| { |
| using namespace std; |
| |
| vector<int> v; |
| vector<int>::iterator it = v.begin(); |
| *it; // no-warning |
| v.insert( it, 1 ); // no-warning |
| *it; // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}} |
| it = v.insert( it, 1 ); // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}} |
| *it; // no-warning |
| } |
| |
| // using reserve eliminates some warnings |
| void foo3() |
| { |
| std::vector<long> v; |
| std::vector<long>::iterator b = v.begin(); |
| v.reserve( 100 ); |
| |
| // iterator assigned before the reserve is still invalidated |
| *b; // expected-warning{{Attempt to use an iterator made invalid by call to 'reserve'}} |
| b = v.begin(); |
| v.insert( b, 1 ); // no-warning |
| |
| // iterator after assignment is still valid (probably) |
| *b; // no-warning |
| } |
| |
| // check on copying one iterator to another |
| void foo4() |
| { |
| std::vector<float> v, vv; |
| std::vector<float>::iterator it = v.begin(); |
| *it; // no-warning |
| v = vv; |
| *it; // expected-warning{{Attempt to use an iterator made invalid by copying another container to its container}} |
| } |
| |