aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorSam Panzer <espanz@gmail.com>2012-08-24 23:46:42 +0000
committerSam Panzer <espanz@gmail.com>2012-08-24 23:46:42 +0000
commit34cbca9ee05a44a7c975cb3d63518b55193b321f (patch)
treeef96a9b9bacaaa8d1f1a73e8e1fb14093d78c024 /test
parentc6bcc7acee726923819d4e08de3cb6db41b88d69 (diff)
loop-convert, a C++11 for loop modernizer
A new Clang-based tool which converts for loops to use the range-based syntax new to C++11. Three kinds of loops can be converted: - Loops over statically allocated arrays - Loops over containers, using iterators - Loops over array-like containers, using operator[] and at() Each transformation is assigned a confidence level by the tool. The minimum require confidence level to actually apply the transformation can be specified on the command line, but the default level should be fine for most code. Like other tools based on RefactoringTool, it is easiest to use this tool with a compilation database. git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@162627 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/loop-convert/Inputs/negative-header.h14
-rw-r--r--test/loop-convert/Inputs/structures.h140
-rw-r--r--test/loop-convert/array.cpp156
-rw-r--r--test/loop-convert/confidence.cpp36
-rw-r--r--test/loop-convert/dependency.cpp27
-rw-r--r--test/loop-convert/iterator.cpp106
-rw-r--r--test/loop-convert/naming.cpp68
-rw-r--r--test/loop-convert/negative-iterator.cpp161
-rw-r--r--test/loop-convert/negative-multi-end-call.cpp65
-rw-r--r--test/loop-convert/negative-pseudoarray-extra.cpp30
-rw-r--r--test/loop-convert/negative-pseudoarray.cpp130
-rw-r--r--test/loop-convert/negative.cpp125
-rw-r--r--test/loop-convert/nesting.cpp58
-rw-r--r--test/loop-convert/nocompile.cpp23
-rw-r--r--test/loop-convert/pseudoarray.cpp68
-rw-r--r--test/loop-convert/single-iterator.cpp118
17 files changed, 1326 insertions, 1 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index b93f9514..9c0d1824 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -22,7 +22,7 @@ set(CLANG_TOOLS_TEST_DEPS
clang clang-headers FileCheck count not
# Individual tools we test.
- remove-cstr-calls
+ remove-cstr-calls loop-convert
)
add_lit_testsuite(check-clang-tools "Running the Clang extra tools' regression tests"
diff --git a/test/loop-convert/Inputs/negative-header.h b/test/loop-convert/Inputs/negative-header.h
new file mode 100644
index 00000000..aaa1c9e3
--- /dev/null
+++ b/test/loop-convert/Inputs/negative-header.h
@@ -0,0 +1,14 @@
+#ifndef _CLANG_TOOLS_EXTRA_H_
+#define _CLANG_TOOLS_EXTRA_H_
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+static void loopInHeader() {
+ const int N = 10;
+ int arr[N];
+ int sum = 0;
+ for (int i = 0; i < N; ++i)
+ sum += arr[i];
+}
+
+#endif //_CLANG_TOOLS_EXTRA_H_
diff --git a/test/loop-convert/Inputs/structures.h b/test/loop-convert/Inputs/structures.h
new file mode 100644
index 00000000..412f97ee
--- /dev/null
+++ b/test/loop-convert/Inputs/structures.h
@@ -0,0 +1,140 @@
+#ifndef _LLVM_TOOLS_CLANG_TOOLS_TESTS_TOOLING_STRUCTURES_H_
+#define _LLVM_TOOLS_CLANG_TOOLS_TESTS_TOOLING_STRUCTURES_H_
+
+extern "C" {
+extern int printf(const char *restrict, ...);
+}
+
+struct Val {int x; void g(); };
+
+struct MutableVal {
+ void constFun(int) const;
+ void nonConstFun(int, int);
+ void constFun(MutableVal &) const;
+ void constParamFun(const MutableVal &) const;
+ void nonConstParamFun(const MutableVal &);
+ int x;
+};
+
+struct S {
+ typedef MutableVal *iterator;
+ typedef const MutableVal *const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ iterator begin();
+ iterator end();
+};
+
+struct T {
+ struct iterator {
+ int& operator*();
+ const int& operator*()const;
+ iterator& operator ++();
+ bool operator!=(const iterator &other);
+ void insert(int);
+ int x;
+ };
+ iterator begin();
+ iterator end();
+};
+
+struct U {
+ struct iterator {
+ Val& operator*();
+ const Val& operator*()const;
+ iterator& operator ++();
+ bool operator!=(const iterator &other);
+ Val *operator->();
+ };
+ iterator begin();
+ iterator end();
+ int x;
+};
+
+struct X {
+ S s;
+ T t;
+ U u;
+ S getS();
+};
+
+template<typename ElemType>
+class dependent{
+ public:
+ struct iterator_base {
+ const ElemType& operator*()const;
+ iterator_base& operator ++();
+ bool operator!=(const iterator_base &other) const;
+ const ElemType *operator->() const;
+ };
+
+ struct iterator : iterator_base {
+ ElemType& operator*();
+ iterator& operator ++();
+ ElemType *operator->();
+ };
+
+ typedef iterator_base const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ iterator begin();
+ iterator end();
+ unsigned size() const;
+ ElemType & operator[](unsigned);
+ const ElemType & operator[](unsigned) const;
+ ElemType & at(unsigned);
+ const ElemType & at(unsigned) const;
+
+ // Intentionally evil.
+ dependent<ElemType> operator*();
+
+ void foo();
+ void constFoo() const;
+};
+
+template<typename First, typename Second>
+class doublyDependent{
+ public:
+ struct Value {
+ First first;
+ Second second;
+ };
+
+ struct iterator_base {
+ const Value& operator*()const;
+ iterator_base& operator ++();
+ bool operator!=(const iterator_base &other) const;
+ const Value *operator->() const;
+ };
+
+ struct iterator : iterator_base {
+ Value& operator*();
+ Value& operator ++();
+ Value *operator->();
+ };
+
+ typedef iterator_base const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ iterator begin();
+ iterator end();
+};
+
+template<typename Contained>
+class transparent {
+ public:
+ Contained *at();
+ Contained *operator->();
+ Contained operator*();
+};
+
+template<typename IteratorType>
+struct Nested {
+ typedef IteratorType* iterator;
+ IteratorType *operator->();
+ IteratorType operator*();
+ iterator begin();
+ iterator end();
+};
+
+#endif // _LLVM_TOOLS_CLANG_TOOLS_TESTS_TOOLING_STRUCTURES_H_
diff --git a/test/loop-convert/array.cpp b/test/loop-convert/array.cpp
new file mode 100644
index 00000000..8853dd6f
--- /dev/null
+++ b/test/loop-convert/array.cpp
@@ -0,0 +1,156 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: cp %t.cpp %t.base
+// RUN: loop-convert -count-only . %t.cpp -- -I %S/Inputs > %T/out \
+// RUN: && FileCheck -check-prefix=COUNTONLY -input-file=%T/out %s \
+// RUN: && diff %t.cpp %t.base
+
+#include "structures.h"
+
+const int N = 6;
+const int NMinusOne = N - 1;
+int arr[N] = {1, 2, 3, 4, 5, 6};
+int (*pArr)[N] = &arr;
+
+void f() {
+ int sum = 0;
+ // Update the number of correctly converted loops as this test changes:
+ // COUNTONLY: 15 converted
+ // COUNTONLY-NEXT: 0 potentially conflicting
+ // COUNTONLY-NEXT: 0 change(s) rejected
+
+ for (int i = 0; i < N; ++i) {
+ sum += arr[i];
+ int k;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr) {
+ // CHECK-NEXT: sum += [[VAR]];
+ // CHECK-NEXT: int k;
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ printf("Fibonacci number is %d\n", arr[i]);
+ sum += arr[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ for (int i = 0; i < N; ++i) {
+ int x = arr[i];
+ int y = arr[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: int x = [[VAR]];
+ // CHECK-NEXT: int y = [[VAR]] + 2;
+
+ for (int i = 0; i < N; ++i) {
+ int x = N;
+ x = arr[i];
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: int x = N;
+ // CHECK-NEXT: x = [[VAR]];
+
+ for (int i = 0; i < N; ++i) {
+ arr[i] += 1;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr) {
+ // CHECK-NEXT: [[VAR]] += 1;
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ int x = arr[i] + 2;
+ arr[i] ++;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: int x = [[VAR]] + 2;
+ // CHECK-NEXT: [[VAR]] ++;
+
+ for (int i = 0; i < N; ++i) {
+ arr[i] = 4 + arr[i];
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: [[VAR]] = 4 + [[VAR]];
+
+ for (int i = 0; i < NMinusOne + 1; ++i) {
+ sum += arr[i];
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr) {
+ // CHECK-NEXT: sum += [[VAR]];
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ printf("Fibonacci number %d has address %p\n", arr[i], &arr[i]);
+ sum += arr[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr)
+ // CHECK-NEXT: printf("Fibonacci number %d has address %p\n", [[VAR]], &[[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ Val teas[N];
+ for (int i = 0; i < N; ++i) {
+ teas[i].g();
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : teas) {
+ // CHECK-NEXT: [[VAR]].g();
+ // CHECK-NEXT: }
+}
+
+struct HasArr {
+ int Arr[N];
+ Val ValArr[N];
+ void implicitThis() {
+ for (int i = 0; i < N; ++i) {
+ printf("%d", Arr[i]);
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : Arr) {
+ // CHECK-NEXT: printf("%d", [[VAR]]);
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ printf("%d", ValArr[i].x);
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : ValArr) {
+ // CHECK-NEXT: printf("%d", [[VAR]].x);
+ // CHECK-NEXT: }
+ }
+
+ void explicitThis() {
+ for (int i = 0; i < N; ++i) {
+ printf("%d", this->Arr[i]);
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : this->Arr) {
+ // CHECK-NEXT: printf("%d", [[VAR]]);
+ // CHECK-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ printf("%d", this->ValArr[i].x);
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : this->ValArr) {
+ // CHECK-NEXT: printf("%d", [[VAR]].x);
+ // CHECK-NEXT: }
+ }
+};
+
+// Loops whose bounds are value-dependent shold not be converted.
+template<int N>
+void dependentExprBound() {
+ for (int i = 0; i < N; ++i)
+ arr[i] = 0;
+ // CHECK: for (int i = 0; i < N; ++i)
+ // CHECK-NEXT: arr[i] = 0;
+}
+template void dependentExprBound<20>();
+
+void memberFunctionPointer() {
+ Val v;
+ void (Val::*mfpArr[N])(void) = { &Val::g };
+ for (int i = 0; i < N; ++i)
+ (v.*mfpArr[i])();
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : mfpArr)
+ // CHECK-NEXT: (v.*[[VAR]])();
+}
diff --git a/test/loop-convert/confidence.cpp b/test/loop-convert/confidence.cpp
new file mode 100644
index 00000000..61f6ebe0
--- /dev/null
+++ b/test/loop-convert/confidence.cpp
@@ -0,0 +1,36 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: loop-convert . %t.cpp -A2 -- -I %S/Inputs \
+// RUN: && FileCheck -check-prefix=RISKY -input-file=%t.cpp %s
+
+#include "structures.h"
+
+void f() {
+ const int N = 5;
+ const int M = 7;
+ int (*pArr)[N];
+ int Arr[N][M];
+ int sum = 0;
+
+ for (int i = 0; i < M; ++i) {
+ sum += Arr[0][i];
+ }
+ // CHECK: for (int i = 0; i < M; ++i) {
+ // CHECK-NEXT: sum += Arr[0][i];
+ // CHECK-NEXT: }
+ // RISKY: for (auto & [[VAR:[a-z_]+]] : Arr[0]) {
+ // RISKY-NEXT: sum += [[VAR]];
+ // RISKY-NEXT: }
+
+ for (int i = 0; i < N; ++i) {
+ sum += (*pArr)[i];
+ }
+ // RISKY: for (auto & [[VAR:[a-z_]+]] : *pArr) {
+ // RISKY-NEXT: sum += [[VAR]];
+ // RISKY-NEXT: }
+ // CHECK: for (int i = 0; i < N; ++i) {
+ // CHECK-NEXT: sum += (*pArr)[i];
+ // CHECK-NEXT: }
+}
diff --git a/test/loop-convert/dependency.cpp b/test/loop-convert/dependency.cpp
new file mode 100644
index 00000000..2f960052
--- /dev/null
+++ b/test/loop-convert/dependency.cpp
@@ -0,0 +1,27 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- && FileCheck -input-file=%t.cpp %s
+
+void f() {
+ const int N = 6;
+ const int M = 8;
+ int arr[N][M];
+
+ for (int i = 0; i < N; ++i) {
+ int a = 0;
+ int b = arr[i][a];
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : arr) {
+ // CHECK-NEXT: int a = 0;
+ // CHECK-NEXT: int b = [[VAR]][a];
+ // CHECK-NEXT: }
+
+ for (int j = 0; j < M; ++j) {
+ int a = 0;
+ int b = arr[a][j];
+ }
+ // CHECK: for (int j = 0; j < M; ++j) {
+ // CHECK-NEXT: int a = 0;
+ // CHECK-NEXT: int b = arr[a][j];
+ // CHECK-NEXT: }
+}
diff --git a/test/loop-convert/iterator.cpp b/test/loop-convert/iterator.cpp
new file mode 100644
index 00000000..8f410200
--- /dev/null
+++ b/test/loop-convert/iterator.cpp
@@ -0,0 +1,106 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: rm -rf %t.cpp
+
+#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 ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : t)
+ // CHECK-NEXT: printf("I found %d\n", [[VAR]]);
+
+ T *pt;
+ for (T::iterator it = pt->begin(), e = pt->end(); it != e; ++it) {
+ printf("I found %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : *pt)
+ // CHECK-NEXT: printf("I found %d\n", [[VAR]]);
+
+ 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 ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).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 ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : *ps)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ printf("s has value %d\n", it->x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: printf("s has value %d\n", [[VAR]].x);
+
+ for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ it->x = 3;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: [[VAR]].x = 3;
+
+ for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ (*it).x = 3;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: ([[VAR]]).x = 3;
+
+ for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
+ it->nonConstFun(4, 5);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: [[VAR]].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 ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: printf("s has value %d\n", [[VAR]].x);
+
+ for (U::iterator it = u.begin(), e = u.end(); it != e; ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ U::iterator A;
+ for (U::iterator i = u.begin(), e = u.end(); i != e; ++i)
+ int k = A->x + i->x;
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: int k = A->x + [[VAR]].x;
+
+ 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 ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+
+ for (dependent<int>::const_iterator it(v.begin()), e = v.end();
+ it != e; ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+
+ 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 ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : intmap)
+ // CHECK-NEXT: printf("intmap[%d] = %d", [[VAR]].first, [[VAR]].second);
+
+}
diff --git a/test/loop-convert/naming.cpp b/test/loop-convert/naming.cpp
new file mode 100644
index 00000000..0bfef339
--- /dev/null
+++ b/test/loop-convert/naming.cpp
@@ -0,0 +1,68 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+const int N = 10;
+int nums[N];
+int sum = 0;
+
+Val Arr[N];
+Val &func(Val &);
+
+void aliasing() {
+ // The extra blank braces are left as a placeholder for after the variable
+ // declaration is deleted.
+ for (int i = 0; i < N; ++i) {
+ Val &t = Arr[i]; { }
+ int y = t.x;
+ }
+ // CHECK: for (auto & t : Arr)
+ // CHECK-NEXT: { }
+ // CHECK-NEXT: int y = t.x;
+
+ for (int i = 0; i < N; ++i) {
+ Val &t = Arr[i];
+ int y = t.x;
+ int z = Arr[i].x + t.x;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : Arr)
+ // CHECK-NEXT: Val &t = [[VAR]];
+ // CHECK-NEXT: int y = t.x;
+ // CHECK-NEXT: int z = [[VAR]].x + t.x;
+
+ for (int i = 0; i < N; ++i) {
+ Val t = Arr[i];
+ int y = t.x;
+ int z = Arr[i].x + t.x;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : Arr)
+ // CHECK-NEXT: Val t = [[VAR]];
+ // CHECK-NEXT: int y = t.x;
+ // CHECK-NEXT: int z = [[VAR]].x + t.x;
+
+ for (int i = 0; i < N; ++i) {
+ Val &t = func(Arr[i]);
+ int y = t.x;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : Arr)
+ // CHECK-NEXT: Val &t = func([[VAR]]);
+ // CHECK-NEXT: int y = t.x;
+}
+
+void sameNames() {
+ int num = 0;
+ for (int i = 0; i < N; ++i) {
+ printf("Fibonacci number is %d\n", nums[i]);
+ sum += nums[i] + 2 + num;
+ (void) nums[i];
+ }
+ // CHECK: int num = 0;
+ // CHECK-NEXT: for (auto & [[VAR:[a-z_]+]] : nums)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2 + num;
+ // CHECK-NOT: (void) num;
+ // CHECK: }
+}
diff --git a/test/loop-convert/negative-iterator.cpp b/test/loop-convert/negative-iterator.cpp
new file mode 100644
index 00000000..041bbee4
--- /dev/null
+++ b/test/loop-convert/negative-iterator.cpp
@@ -0,0 +1,161 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+S s;
+T t;
+U u;
+
+struct BadBeginEnd : T {
+ iterator notBegin();
+ iterator notEnd();
+};
+
+void notBeginOrEnd() {
+ BadBeginEnd Bad;
+ for (T::iterator i = Bad.notBegin(), e = Bad.end(); i != e; ++i)
+ int k = *i;
+
+ for (T::iterator i = Bad.begin(), e = Bad.notEnd(); i != e; ++i)
+ int k = *i;
+}
+
+void badLoopShapes() {
+ for (T::iterator i = t.begin(), e = t.end(), f = e; i != e; ++i)
+ int k = *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); i != e; )
+ int k = *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); ; ++i)
+ int k = *i;
+
+ T::iterator outsideI;
+ T::iterator outsideE;
+
+ for (; outsideI != outsideE ; ++outsideI)
+ int k = *outsideI;
+}
+
+void iteratorArrayMix() {
+ int lower;
+ const int N = 6;
+ for (T::iterator i = t.begin(), e = t.end(); lower < N; ++i)
+ int k = *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); lower < N; ++lower)
+ int k = *i;
+}
+
+struct ExtraConstructor : T::iterator {
+ ExtraConstructor(T::iterator, int);
+ explicit ExtraConstructor(T::iterator);
+};
+
+void badConstructor() {
+ for (T::iterator i = ExtraConstructor(t.begin(), 0), e = t.end();
+ i != e; ++i)
+ int k = *i;
+ for (T::iterator i = ExtraConstructor(t.begin()), e = t.end(); i != e; ++i)
+ int k = *i;
+}
+
+void iteratorMemberUsed() {
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ i.x = *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ int k = i.x + *i;
+
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ int k = e.x + *i;
+}
+
+void iteratorMethodCalled() {
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ i.insert(3);
+
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ if (i != i)
+ int k = 3;
+}
+
+void iteratorOperatorCalled() {
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ int k = *(++i);
+
+ for (S::iterator i = s.begin(), e = s.end(); i != e; ++i)
+ MutableVal k = *(++i);
+}
+
+void differentContainers() {
+ T other;
+ for (T::iterator i = t.begin(), e = other.end(); i != e; ++i)
+ int k = *i;
+
+ for (T::iterator i = other.begin(), e = t.end(); i != e; ++i)
+ int k = *i;
+
+ S otherS;
+ for (S::iterator i = s.begin(), e = otherS.end(); i != e; ++i)
+ MutableVal k = *i;
+
+ for (S::iterator i = otherS.begin(), e = s.end(); i != e; ++i)
+ MutableVal k = *i;
+}
+
+void wrongIterators() {
+ T::iterator other;
+ for (T::iterator i = t.begin(), e = t.end(); i != other; ++i)
+ int k = *i;
+}
+
+struct EvilArrow : U {
+ // Please, no one ever write code like this.
+ U* operator->();
+};
+
+void differentMemberAccessTypes() {
+ EvilArrow A;
+ for (EvilArrow::iterator i = A.begin(), e = A->end(); i != e; ++i)
+ Val k = *i;
+ for (EvilArrow::iterator i = A->begin(), e = A.end(); i != e; ++i)
+ Val k = *i;
+}
+
+void f(const T::iterator &it, int);
+void f(const T &it, int);
+void g(T &it, int);
+
+void iteratorPassedToFunction() {
+ for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+ f(i, *i);
+}
+
+// FIXME: Disallow this except for containers passed by value and/or const
+// reference. Or maybe this is correct enough for any container?
+void containerPassedToFunction() {
+// for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+// f(t, *i);
+// for (T::iterator i = t.begin(), e = t.end(); i != e; ++i)
+// g(t, *i);
+}
+
+// FIXME: These tests can be removed if this tool ever does enough analysis to
+// decide that this is a safe transformation.
+// Until then, we don't want it applied.
+void iteratorDefinedOutside() {
+ T::iterator theEnd = t.end();
+ for (T::iterator i = t.begin(); i != theEnd; ++i)
+ int k = *i;
+
+ T::iterator theBegin = t.begin();
+ for (T::iterator e = t.end(); theBegin != e; ++theBegin)
+ int k = *theBegin;
+}
diff --git a/test/loop-convert/negative-multi-end-call.cpp b/test/loop-convert/negative-multi-end-call.cpp
new file mode 100644
index 00000000..cc15ce56
--- /dev/null
+++ b/test/loop-convert/negative-multi-end-call.cpp
@@ -0,0 +1,65 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert -A0 . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+S s;
+T t;
+U u;
+
+void multipleEnd() {
+ for (S::iterator i = s.begin(); i != s.end(); ++i)
+ MutableVal k = *i;
+
+ for (T::iterator i = t.begin(); i != t.end(); ++i)
+ int k = *i;
+
+ for (U::iterator i = u.begin(); i != u.end(); ++i)
+ Val k = *i;
+}
+
+void f(X);
+void f(S);
+void f(T);
+
+void complexContainer() {
+ X x;
+ for (S::iterator i = x.s.begin(), e = x.s.end(); i != e; ++i) {
+ f(x);
+ MutableVal k = *i;
+ }
+
+ for (T::iterator i = x.t.begin(), e = x.t.end(); i != e; ++i) {
+ f(x);
+ int k = *i;
+ }
+
+ for (S::iterator i = x.s.begin(), e = x.s.end(); i != e; ++i) {
+ f(x.s);
+ MutableVal k = *i;
+ }
+
+ for (T::iterator i = x.t.begin(), e = x.t.end(); i != e; ++i) {
+ f(x.t);
+ int k = *i;
+ }
+
+ for (S::iterator i = x.getS().begin(), e = x.getS().end(); i != e; ++i) {
+ f(x.getS());
+ MutableVal k = *i;
+ }
+
+ X exes[5];
+ int index = 0;
+
+ for (S::iterator i = exes[index].getS().begin(),
+ e = exes[index].getS().end(); i != e; ++i) {
+ index++;
+ MutableVal k = *i;
+ }
+}
diff --git a/test/loop-convert/negative-pseudoarray-extra.cpp b/test/loop-convert/negative-pseudoarray-extra.cpp
new file mode 100644
index 00000000..224a87bf
--- /dev/null
+++ b/test/loop-convert/negative-pseudoarray-extra.cpp
@@ -0,0 +1,30 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert -A1 . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+const int N = 6;
+dependent<int> v;
+dependent<int> *pv;
+
+int sum = 0;
+
+// Checks to see that non-const member functions are not called on the container
+// object.
+// These could be conceivably allowed with a lower required confidence level.
+void memberFunctionCalled() {
+ for (int i = 0; i < v.size(); ++i) {
+ sum += v[i];
+ v.foo();
+ }
+
+ for (int i = 0; i < v.size(); ++i) {
+ sum += v[i];
+ dependent<int>::iterator it = v.begin();
+ }
+}
diff --git a/test/loop-convert/negative-pseudoarray.cpp b/test/loop-convert/negative-pseudoarray.cpp
new file mode 100644
index 00000000..e5b3a1d4
--- /dev/null
+++ b/test/loop-convert/negative-pseudoarray.cpp
@@ -0,0 +1,130 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert -A1 . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+const int N = 6;
+dependent<int> v;
+dependent<int> *pv;
+
+transparent<dependent<int> > cv;
+int sum = 0;
+
+// Checks for the index start and end:
+void indexStartAndEnd() {
+ for (int i = 0; i < v.size() + 1; ++i)
+ sum += v[i];
+
+ for (int i = 0; i < v.size() - 1; ++i)
+ sum += v[i];
+
+ for (int i = 1; i < v.size(); ++i)
+ sum += v[i];
+
+ for (int i = 1; i < v.size(); ++i)
+ sum += v[i];
+
+ for (int i = 0; ; ++i)
+ sum += (*pv)[i];
+}
+
+// Checks for invalid increment steps:
+void increment() {
+ for (int i = 0; i < v.size(); --i)
+ sum += v[i];
+
+ for (int i = 0; i < v.size(); i)
+ sum += v[i];
+
+ for (int i = 0; i < v.size();)
+ sum += v[i];
+
+ for (int i = 0; i < v.size(); i += 2)
+ sum ++;
+}
+
+// Checks to make sure that the index isn't used outside of the container:
+void indexUse() {
+ for (int i = 0; i < v.size(); ++i)
+ v[i] += 1 + i;
+}
+
+// Checks for incorrect loop variables.
+void mixedVariables() {
+ int badIndex;
+ for (int i = 0; badIndex < v.size(); ++i)
+ sum += v[i];
+
+ for (int i = 0; i < v.size(); ++badIndex)
+ sum += v[i];
+
+ for (int i = 0; badIndex < v.size(); ++badIndex)
+ sum += v[i];
+
+ for (int i = 0; badIndex < v.size(); ++badIndex)
+ sum += v[badIndex];
+}
+
+// Checks for an array indexed in addition to the container.
+void multipleArrays() {
+ int badArr[N];
+
+ for (int i = 0; i < v.size(); ++i)
+ sum += v[i] + badArr[i];
+
+ for (int i = 0; i < v.size(); ++i)
+ sum += badArr[i];
+
+ for (int i = 0; i < v.size(); ++i) {
+ int k = badArr[i];
+ sum += k + 2;
+ }
+
+ for (int i = 0; i < v.size(); ++i) {
+ int k = badArr[i];
+ sum += v[i] + k;
+ }
+}
+
+// Checks for multiple containers being indexed container.
+void multipleContainers() {
+ dependent<int> badArr;
+
+ for (int i = 0; i < v.size(); ++i)
+ sum += v[i] + badArr[i];
+
+ for (int i = 0; i < v.size(); ++i)
+ sum += badArr[i];
+
+ for (int i = 0; i < v.size(); ++i) {
+ int k = badArr[i];
+ sum += k + 2;
+ }
+
+ for (int i = 0; i < v.size(); ++i) {
+ int k = badArr[i];
+ sum += v[i] + k;
+ }
+}
+
+// Check to make sure that dereferenced pointers-to-containers behave nicely
+void derefContainer() {
+ // Note the dependent<T>::operator*() returns another dependent<T>.
+ // This test makes sure that we don't allow an arbitrary number of *'s.
+ for (int i = 0; i < pv->size(); ++i)
+ sum += (**pv).at(i);
+
+ for (int i = 0; i < pv->size(); ++i)
+ sum += (**pv)[i];
+}
+
+void wrongEnd() {
+ int bad;
+ for (int i = 0, e = v.size(); i < bad; ++i)
+ sum += v[i];
+}
diff --git a/test/loop-convert/negative.cpp b/test/loop-convert/negative.cpp
new file mode 100644
index 00000000..55975572
--- /dev/null
+++ b/test/loop-convert/negative.cpp
@@ -0,0 +1,125 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %S/Inputs/negative-header.h > \
+// RUN: %T/negative-header.h
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs/ \
+// RUN: && FileCheck -input-file=%t.cpp %s \
+// RUN: && FileCheck -input-file=%T/negative-header.h \
+// RUN: %S/Inputs/negative-header.h
+
+#include "negative-header.h"
+#include "structures.h"
+
+// Single FileCheck line to make sure that no loops are converted.
+// CHECK-NOT: for ({{.*[^:]:[^:].*}})
+
+const int N = 6;
+int arr[N] = {1, 2, 3, 4, 5, 6};
+int (*pArr)[N] = &arr;
+int sum = 0;
+
+// Checks for the index start and end:
+void indexStartAndEnd() {
+ for (int i = 0; i < N + 1; ++i)
+ sum += arr[i];
+
+ for (int i = 0; i < N - 1; ++i)
+ sum += arr[i];
+
+ for (int i = 1; i < N; ++i)
+ sum += arr[i];
+
+ for (int i = 1; i < N; ++i)
+ sum += arr[i];
+
+ for (int i = 0; ; ++i)
+ sum += (*pArr)[i];
+}
+
+// Checks for invalid increment steps:
+void increment() {
+ for (int i = 0; i < N; --i)
+ sum += arr[i];
+
+ for (int i = 0; i < N; i)
+ sum += arr[i];
+
+ for (int i = 0; i < N;)
+ sum += arr[i];
+
+ for (int i = 0; i < N; i += 2)
+ sum ++;
+}
+
+// Checks to make sure that the index isn't used outside of the array:
+void indexUse() {
+ for (int i = 0; i < N; ++i)
+ arr[i] += 1 + i;
+}
+
+// Check for loops that don't mention arrays
+void noArray() {
+ for (int i = 0; i < N; ++i)
+ sum += i;
+
+ for (int i = 0; i < N; ++i) { }
+
+ for (int i = 0; i < N; ++i) ;
+}
+
+// Checks for incorrect loop variables.
+void mixedVariables() {
+ int badIndex;
+ for (int i = 0; badIndex < N; ++i)
+ sum += arr[i];
+
+ for (int i = 0; i < N; ++badIndex)
+ sum += arr[i];
+
+ for (int i = 0; badIndex < N; ++badIndex)
+ sum += arr[i];
+
+ for (int i = 0; badIndex < N; ++badIndex)
+ sum += arr[badIndex];
+}
+
+// Checks for multiple arrays indexed.
+void multipleArrays() {
+ int badArr[N];
+
+ for (int i = 0; i < N; ++i)
+ sum += arr[i] + badArr[i];
+
+ for (int i = 0; i < N; ++i) {
+ int k = badArr[i];
+ sum += arr[i] + k;
+ }
+}
+
+struct HasArr {
+ int Arr[N];
+ Val ValArr[N];
+};
+
+struct HasIndirectArr {
+ HasArr HA;
+ void implicitThis() {
+ for (int i = 0; i < N; ++i) {
+ printf("%d", HA.Arr[i]);
+ }
+
+ for (int i = 0; i < N; ++i) {
+ printf("%d", HA.ValArr[i].x);
+ }
+ }
+
+ void explicitThis() {
+ for (int i = 0; i < N; ++i) {
+ printf("%d", this->HA.Arr[i]);
+ }
+
+ for (int i = 0; i < N; ++i) {
+ printf("%d", this->HA.ValArr[i].x);
+ }
+ }
+};
diff --git a/test/loop-convert/nesting.cpp b/test/loop-convert/nesting.cpp
new file mode 100644
index 00000000..8e960a89
--- /dev/null
+++ b/test/loop-convert/nesting.cpp
@@ -0,0 +1,58 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+
+#include "structures.h"
+
+void f() {
+ const int N = 10;
+ const int M = 15;
+ Val Arr[N];
+ for (int i = 0; i < N; ++i) {
+ for (int j = 0; j < N; ++j) {
+ int k = Arr[i].x + Arr[j].x;
+ // The repeat is there to allow FileCheck to make sure the two variable
+ // names aren't the same.
+ int l = Arr[i].x + Arr[j].x;
+ }
+ }
+ // CHECK: for (auto & [[VAR:[a-zA-Z_]+]] : Arr)
+ // CHECK-NEXT: for (auto & [[INNERVAR:[a-zA-Z_]+]] : Arr)
+ // CHECK-NEXT: int k = [[VAR]].x + [[INNERVAR]].x;
+ // CHECK-NOT: int l = [[VAR]].x + [[VAR]].x;
+
+ Val Nest[N][M];
+ for (int i = 0; i < N; ++i) {
+ for (int j = 0; j < M; ++j) {
+ printf("Got item %d", Nest[i][j].x);
+ }
+ }
+ // The inner loop is also convertible, but doesn't need to be converted
+ // immediately. Update this test when that changes!
+ // CHECK: for (auto & [[VAR:[a-zA-Z_]+]] : Nest)
+ // CHECK-NEXT: for (int j = 0; j < M; ++j)
+ // CHECK-NEXT: printf("Got item %d", [[VAR]][j].x);
+
+ // Note that the order of M and N are switched for this test.
+ for (int j = 0; j < M; ++j) {
+ for (int i = 0; i < N; ++i) {
+ printf("Got item %d", Nest[i][j].x);
+ }
+ }
+ // CHECK-NOT: for (auto & {{[a-zA-Z_]+}} : Nest[i])
+ // CHECK: for (int j = 0; j < M; ++j)
+ // CHECK-NEXT: for (auto & [[VAR:[a-zA-Z_]+]] : Nest)
+ // CHECK-NEXT: printf("Got item %d", [[VAR]][j].x);
+ Nested<T> NestT;
+ for (Nested<T>::iterator I = NestT.begin(), E = NestT.end(); I != E; ++I) {
+ for (T::iterator TI = (*I).begin(), TE = (*I).end(); TI != TE; ++TI) {
+ printf("%d", *TI);
+ }
+ }
+ // The inner loop is also convertible, but doesn't need to be converted
+ // immediately. Update this test when that changes!
+ // CHECK: for (auto & [[VAR:[a-zA-Z_]+]] : NestT) {
+ // CHECK-NEXT: for (T::iterator TI = ([[VAR]]).begin(), TE = ([[VAR]]).end(); TI != TE; ++TI) {
+ // CHECK-NEXT: printf("%d", *TI);
+}
diff --git a/test/loop-convert/nocompile.cpp b/test/loop-convert/nocompile.cpp
new file mode 100644
index 00000000..32390102
--- /dev/null
+++ b/test/loop-convert/nocompile.cpp
@@ -0,0 +1,23 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: || FileCheck -input-file=%t.cpp %s
+// Note that this test expects the compilation to fail!
+
+void valid() {
+ const int arr[5];
+ int sum = 0;
+ for (int i = 0; i < 5; ++i) {
+ sum += arr[i];
+ }
+}
+void hasSyntaxError = 3;
+// CHECK: void valid() {
+// CHECK-NEXT: const int arr[5];
+// CHECK-NEXT: int sum = 0;
+// CHECK-NEXT: for (int i = 0; i < 5; ++i) {
+// CHECK-NEXT: sum += arr[i];
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+
+// CHECK-NEXT: void hasSyntaxError = 3;
diff --git a/test/loop-convert/pseudoarray.cpp b/test/loop-convert/pseudoarray.cpp
new file mode 100644
index 00000000..b47616d0
--- /dev/null
+++ b/test/loop-convert/pseudoarray.cpp
@@ -0,0 +1,68 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: rm -rf %t.cpp
+#include "structures.h"
+
+const int N = 6;
+dependent<int> v;
+dependent<int> *pv;
+
+transparent<dependent<int> > cv;
+
+void f() {
+ int sum = 0;
+ for (int i = 0, e = v.size(); i < e; ++i) {
+ printf("Fibonacci number is %d\n", v[i]);
+ sum += v[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ for (int i = 0, e = v.size(); i < e; ++i) {
+ printf("Fibonacci number is %d\n", v.at(i));
+ sum += v.at(i) + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ for (int i = 0, e = pv->size(); i < e; ++i) {
+ printf("Fibonacci number is %d\n", pv->at(i));
+ sum += pv->at(i) + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : *pv)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ // This test will fail if size() isn't called repeatedly, since it
+ // returns unsigned int, and 0 is deduced to be signed int.
+ // FIXME: Insert the necessary explicit conversion, or write out the types
+ // explicitly.
+ for (int i = 0; i < pv->size(); ++i) {
+ printf("Fibonacci number is %d\n", (*pv).at(i));
+ sum += (*pv)[i] + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : *pv)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+
+ for (int i = 0; i < cv->size(); ++i) {
+ printf("Fibonacci number is %d\n", cv->at(i));
+ sum += cv->at(i) + 2;
+ }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : *cv)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+ // CHECK-NEXT: sum += [[VAR]] + 2;
+}
+
+// Check for loops that don't mention containers
+void noContainer() {
+ for (auto i = 0; i < v.size(); ++i) { }
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : v) { }
+
+ for (auto i = 0; i < v.size(); ++i) ;
+ // CHECK: for (auto & [[VAR:[a-z_]+]] : v) ;
+}
diff --git a/test/loop-convert/single-iterator.cpp b/test/loop-convert/single-iterator.cpp
new file mode 100644
index 00000000..2359a3ac
--- /dev/null
+++ b/test/loop-convert/single-iterator.cpp
@@ -0,0 +1,118 @@
+// RUN: rm -rf %t.cpp
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: loop-convert . %t.cpp -- -I %S/Inputs \
+// RUN: && FileCheck -input-file=%t.cpp %s
+// RUN: grep -Ev "//\s*[A-Z-]+:" %s > %t.cpp
+// RUN: rm -rf %t.cpp
+
+#include "structures.h"
+
+void complexContainer() {
+ X exes[5];
+ int index = 0;
+
+ for (S::iterator i = exes[index].getS().begin(), e = exes[index].getS().end(); i != e; ++i) {
+ MutableVal k = *i;
+ MutableVal j = *i;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : exes[index].getS())
+ // CHECK-NEXT: MutableVal k = [[VAR]];
+ // CHECK-NEXT: MutableVal j = [[VAR]];
+}
+
+void f() {
+ /// begin()/end() - based for loops here:
+ T t;
+ for (T::iterator it = t.begin(); it != t.end(); ++it) {
+ printf("I found %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : t)
+ // CHECK-NEXT: printf("I found %d\n", [[VAR]]);
+
+ T *pt;
+ for (T::iterator it = pt->begin(); it != pt->end(); ++it) {
+ printf("I found %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]+&? ?}}[[VAR:[a-z_]+]] : *pt)
+ // CHECK-NEXT: printf("I found %d\n", [[VAR]]);
+
+ S s;
+ for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ S *ps;
+ for (S::const_iterator it = ps->begin(); it != ps->end(); ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : *ps)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
+ printf("s has value %d\n", it->x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: printf("s has value %d\n", [[VAR]].x);
+
+ for (S::iterator it = s.begin(); it != s.end(); ++it) {
+ it->x = 3;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: [[VAR]].x = 3;
+
+ for (S::iterator it = s.begin(); it != s.end(); ++it) {
+ (*it).x = 3;
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: ([[VAR]]).x = 3;
+
+ for (S::iterator it = s.begin(); it != s.end(); ++it) {
+ it->nonConstFun(4, 5);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : s)
+ // CHECK-NEXT: [[VAR]].nonConstFun(4, 5);
+
+ U u;
+ for (U::iterator it = u.begin(); it != u.end(); ++it) {
+ printf("s has value %d\n", it->x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: printf("s has value %d\n", [[VAR]].x);
+
+ for (U::iterator it = u.begin(); it != u.end(); ++it) {
+ printf("s has value %d\n", (*it).x);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: printf("s has value %d\n", ([[VAR]]).x);
+
+ U::iterator A;
+ for (U::iterator i = u.begin(); i != u.end(); ++i)
+ int k = A->x + i->x;
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : u)
+ // CHECK-NEXT: int k = A->x + [[VAR]].x;
+
+ dependent<int> v;
+ for (dependent<int>::const_iterator it = v.begin();
+ it != v.end(); ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+
+ for (dependent<int>::const_iterator it(v.begin());
+ it != v.end(); ++it) {
+ printf("Fibonacci number is %d\n", *it);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : v)
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", [[VAR]]);
+
+ doublyDependent<int,int> intmap;
+ for (doublyDependent<int,int>::iterator it = intmap.begin();
+ it != intmap.end(); ++it) {
+ printf("intmap[%d] = %d", it->first, it->second);
+ }
+ // CHECK: for ({{[a-zA-Z_ ]*&? ?}}[[VAR:[a-z_]+]] : intmap)
+ // CHECK-NEXT: printf("intmap[%d] = %d", [[VAR]].first, [[VAR]].second);
+}