| // RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp |
| // RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -std=c++11 |
| // RUN: FileCheck -input-file=%t.cpp %s |
| // RUN: clang-modernize -loop-convert %t.cpp -risk=risky -- -I %S/Inputs |
| // RUN: FileCheck -check-prefix=RISKY -input-file=%t.cpp %s |
| |
| #include "structures.h" |
| |
| void f() { |
| /// begin()/end() - based for loops here: |
| T t; |
| for (T::iterator it = t.begin(), e = t.end(); it != e; ++it) { |
| printf("I found %d\n", *it); |
| } |
| // CHECK: for (auto & elem : t) |
| // CHECK-NEXT: printf("I found %d\n", elem); |
| |
| T *pt; |
| for (T::iterator it = pt->begin(), e = pt->end(); it != e; ++it) { |
| printf("I found %d\n", *it); |
| } |
| // CHECK: for (auto & elem : *pt) |
| // CHECK-NEXT: printf("I found %d\n", elem); |
| |
| S s; |
| for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { |
| printf("s has value %d\n", (*it).x); |
| } |
| // CHECK: for (auto & elem : s) |
| // CHECK-NEXT: printf("s has value %d\n", (elem).x); |
| |
| S *ps; |
| for (S::iterator it = ps->begin(), e = ps->end(); it != e; ++it) { |
| printf("s has value %d\n", (*it).x); |
| } |
| // CHECK: for (auto & p : *ps) |
| // CHECK-NEXT: printf("s has value %d\n", (p).x); |
| |
| for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { |
| printf("s has value %d\n", it->x); |
| } |
| // CHECK: for (auto & elem : s) |
| // CHECK-NEXT: printf("s has value %d\n", elem.x); |
| |
| for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { |
| it->x = 3; |
| } |
| // CHECK: for (auto & elem : s) |
| // CHECK-NEXT: elem.x = 3; |
| |
| for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { |
| (*it).x = 3; |
| } |
| // CHECK: for (auto & elem : s) |
| // CHECK-NEXT: (elem).x = 3; |
| |
| for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { |
| it->nonConstFun(4, 5); |
| } |
| // CHECK: for (auto & elem : s) |
| // CHECK-NEXT: elem.nonConstFun(4, 5); |
| |
| U u; |
| for (U::iterator it = u.begin(), e = u.end(); it != e; ++it) { |
| printf("s has value %d\n", it->x); |
| } |
| // CHECK: for (auto & elem : u) |
| // CHECK-NEXT: printf("s has value %d\n", elem.x); |
| |
| for (U::iterator it = u.begin(), e = u.end(); it != e; ++it) { |
| printf("s has value %d\n", (*it).x); |
| } |
| // CHECK: for (auto & elem : u) |
| // CHECK-NEXT: printf("s has value %d\n", (elem).x); |
| |
| U::iterator A; |
| for (U::iterator i = u.begin(), e = u.end(); i != e; ++i) |
| int k = A->x + i->x; |
| // CHECK: for (auto & elem : u) |
| // CHECK-NEXT: int k = A->x + elem.x; |
| |
| dependent<int> v; |
| for (dependent<int>::iterator it = v.begin(), e = v.end(); |
| it != e; ++it) { |
| printf("Fibonacci number is %d\n", *it); |
| } |
| // CHECK: for (auto & elem : v) { |
| // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); |
| |
| for (dependent<int>::iterator it(v.begin()), e = v.end(); |
| it != e; ++it) { |
| printf("Fibonacci number is %d\n", *it); |
| } |
| // CHECK: for (auto & elem : v) { |
| // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); |
| |
| doublyDependent<int,int> intmap; |
| for (doublyDependent<int,int>::iterator it = intmap.begin(), e = intmap.end(); |
| it != e; ++it) { |
| printf("intmap[%d] = %d", it->first, it->second); |
| } |
| // CHECK: for (auto & elem : intmap) |
| // CHECK-NEXT: printf("intmap[%d] = %d", elem.first, elem.second); |
| |
| // PtrSet's iterator dereferences by value so auto & can't be used. |
| { |
| PtrSet<int*> int_ptrs; |
| for (PtrSet<int*>::iterator I = int_ptrs.begin(), |
| E = int_ptrs.end(); I != E; ++I) { |
| // CHECK: for (auto && int_ptr : int_ptrs) { |
| } |
| } |
| |
| // This container uses an iterator where the derefence type is a typedef of |
| // a reference type. Make sure non-const auto & is still used. A failure here |
| // means canonical types aren't being tested. |
| { |
| TypedefDerefContainer<int> int_ptrs; |
| for (TypedefDerefContainer<int>::iterator I = int_ptrs.begin(), |
| E = int_ptrs.end(); I != E; ++I) { |
| // CHECK: for (auto & int_ptr : int_ptrs) { |
| } |
| } |
| |
| { |
| // Iterators returning an rvalue reference should disqualify the loop from |
| // transformation. |
| RValueDerefContainer<int> container; |
| for (RValueDerefContainer<int>::iterator I = container.begin(), |
| E = container.end(); I != E; ++I) { |
| // CHECK: for (RValueDerefContainer<int>::iterator I = container.begin(), |
| // CHECK-NEXT: E = container.end(); I != E; ++I) { |
| } |
| } |
| } |
| |
| // Tests to verify the proper use of auto where the init variable type and the |
| // initializer type differ or are mostly the same except for const qualifiers. |
| void different_type() { |
| // s.begin() returns a type 'iterator' which is just a non-const pointer and |
| // differs from const_iterator only on the const qualification. |
| S s; |
| for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) { |
| printf("s has value %d\n", (*it).x); |
| } |
| // CHECK: for (const auto & elem : s) |
| // CHECK-NEXT: printf("s has value %d\n", (elem).x); |
| |
| S *ps; |
| for (S::const_iterator it = ps->begin(), e = ps->end(); it != e; ++it) { |
| printf("s has value %d\n", (*it).x); |
| } |
| // CHECK: for (const auto & p : *ps) |
| // CHECK-NEXT: printf("s has value %d\n", (p).x); |
| |
| // v.begin() returns a user-defined type 'iterator' which, since it's |
| // different from const_iterator, disqualifies these loops from |
| // transformation. |
| dependent<int> v; |
| for (dependent<int>::const_iterator it = v.begin(), e = v.end(); |
| it != e; ++it) { |
| printf("Fibonacci number is %d\n", *it); |
| } |
| // CHECK: for (dependent<int>::const_iterator it = v.begin(), e = v.end(); |
| // CHECK-NEXT: it != e; ++it) { |
| // CHECK-NEXT: printf("Fibonacci number is %d\n", *it); |
| |
| for (dependent<int>::const_iterator it(v.begin()), e = v.end(); |
| it != e; ++it) { |
| printf("Fibonacci number is %d\n", *it); |
| } |
| // CHECK: for (dependent<int>::const_iterator it(v.begin()), e = v.end(); |
| // CHECK-NEXT: it != e; ++it) { |
| // CHECK-NEXT: printf("Fibonacci number is %d\n", *it); |
| } |
| |
| // Tests to ensure that an implicit 'this' is picked up as the container. |
| // If member calls are made to 'this' within the loop, the transform becomes |
| // risky as these calls may affect state that affects the loop. |
| class C { |
| public: |
| typedef MutableVal *iterator; |
| typedef const MutableVal *const_iterator; |
| |
| iterator begin(); |
| iterator end(); |
| const_iterator begin() const; |
| const_iterator end() const; |
| |
| void doSomething(); |
| void doSomething() const; |
| |
| void doLoop() { |
| for (iterator I = begin(), E = end(); I != E; ++I) { |
| // CHECK: for (auto & elem : *this) { |
| } |
| for (iterator I = C::begin(), E = C::end(); I != E; ++I) { |
| // CHECK: for (auto & elem : *this) { |
| } |
| for (iterator I = begin(), E = end(); I != E; ++I) { |
| // CHECK: for (iterator I = begin(), E = end(); I != E; ++I) { |
| // RISKY: for (auto & elem : *this) { |
| doSomething(); |
| } |
| for (iterator I = begin(); I != end(); ++I) { |
| // CHECK: for (auto & elem : *this) { |
| } |
| for (iterator I = begin(); I != end(); ++I) { |
| // CHECK: for (iterator I = begin(); I != end(); ++I) { |
| // RISKY: for (auto & elem : *this) { |
| doSomething(); |
| } |
| } |
| |
| void doLoop() const { |
| for (const_iterator I = begin(), E = end(); I != E; ++I) { |
| // CHECK: for (auto & elem : *this) { |
| } |
| for (const_iterator I = C::begin(), E = C::end(); I != E; ++I) { |
| // CHECK: for (auto & elem : *this) { |
| } |
| for (const_iterator I = begin(), E = end(); I != E; ++I) { |
| // CHECK: for (const_iterator I = begin(), E = end(); I != E; ++I) { |
| // RISKY: for (auto & elem : *this) { |
| doSomething(); |
| } |
| } |
| }; |
| |
| class C2 { |
| public: |
| typedef MutableVal *iterator; |
| |
| iterator begin() const; |
| iterator end() const; |
| |
| void doLoop() { |
| // The implicit 'this' will have an Implicit cast to const C2* wrapped |
| // around it. Make sure the replacement still happens. |
| for (iterator I = begin(), E = end(); I != E; ++I) { |
| // CHECK: for (auto & elem : *this) { |
| } |
| } |
| }; |