| // RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -std=c++11 |
| |
| struct Str { |
| Str() = default; |
| Str(const Str &) = default; |
| void constMember(int) const; |
| void nonConstMember(int); |
| bool operator<(const Str &str) const; // const operator. |
| Str &operator=(const Str &str) = default; // non const operator. |
| }; |
| |
| // This class is non-trivially copyable because the copy-constructor and copy |
| // assignment take non-const references. |
| struct ModifiesRightSide { |
| ModifiesRightSide() = default; |
| ModifiesRightSide(ModifiesRightSide &) = default; |
| bool operator<(ModifiesRightSide &) const; |
| ModifiesRightSide &operator=(ModifiesRightSide &) = default; |
| }; |
| |
| template <typename T> |
| void copyArg(T); |
| |
| template <typename T> |
| void nonConstRefArg(T &); |
| |
| // If we define this as a template, the type is deduced to "T&", |
| // and "const (T&) &" is the same as "T& &", and this collapses to "T&". |
| void constRefArg(const Str &); |
| void constRefArg(const ModifiesRightSide &); |
| void constRefArg(const int &); |
| |
| void foo(); |
| |
| const int N = 10; |
| Str Array[N], OtherStr; |
| ModifiesRightSide Right[N], OtherRight; |
| int Ints[N], OtherInt; |
| |
| void memberFunctionsAndOperators() { |
| // Calling const member functions or operator is a const usage. |
| for (int I = 0; I < N; ++I) { |
| Array[I].constMember(0); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert] |
| // CHECK-FIXES: for (auto I : Array) |
| // CHECK-FIXES-NEXT: I.constMember(0); |
| |
| for (int I = 0; I < N; ++I) { |
| if (Array[I] < OtherStr) |
| foo(); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto I : Array) |
| // CHECK-FIXES-NEXT: if (I < OtherStr) |
| for (int I = 0; I < N; ++I) { |
| if (Right[I] < OtherRight) |
| foo(); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (const auto & I : Right) |
| // CHECK-FIXES-NEXT: if (I < OtherRight) |
| |
| // Calling non-const member functions is not. |
| for (int I = 0; I < N; ++I) { |
| Array[I].nonConstMember(0); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & I : Array) |
| // CHECK-FIXES-NEXT: I.nonConstMember(0); |
| |
| for (int I = 0; I < N; ++I) { |
| Array[I] = OtherStr; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & I : Array) |
| // CHECK-FIXES-NEXT: I = OtherStr; |
| |
| for (int I = 0; I < N; ++I) { |
| Right[I] = OtherRight; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & I : Right) |
| // CHECK-FIXES-NEXT: I = OtherRight; |
| } |
| |
| void usedAsParameterToFunctionOrOperator() { |
| // Copying is OK, as long as the copy constructor takes a const-reference. |
| for (int I = 0; I < N; ++I) { |
| copyArg(Array[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto I : Array) |
| // CHECK-FIXES-NEXT: copyArg(I); |
| |
| for (int I = 0; I < N; ++I) { |
| copyArg(Right[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & I : Right) |
| // CHECK-FIXES-NEXT: copyArg(I); |
| |
| // Using as a const reference argument is allowed. |
| for (int I = 0; I < N; ++I) { |
| constRefArg(Array[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto I : Array) |
| // CHECK-FIXES-NEXT: constRefArg(I); |
| |
| for (int I = 0; I < N; ++I) { |
| if (OtherStr < Array[I]) |
| foo(); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto I : Array) |
| // CHECK-FIXES-NEXT: if (OtherStr < I) |
| |
| for (int I = 0; I < N; ++I) { |
| constRefArg(Right[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (const auto & I : Right) |
| // CHECK-FIXES-NEXT: constRefArg(I); |
| |
| // Using as a non-const reference is not. |
| for (int I = 0; I < N; ++I) { |
| nonConstRefArg(Array[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & I : Array) |
| // CHECK-FIXES-NEXT: nonConstRefArg(I); |
| for (int I = 0; I < N; ++I) { |
| nonConstRefArg(Right[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & I : Right) |
| // CHECK-FIXES-NEXT: nonConstRefArg(I); |
| for (int I = 0; I < N; ++I) { |
| if (OtherRight < Right[I]) |
| foo(); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & I : Right) |
| // CHECK-FIXES-NEXT: if (OtherRight < I) |
| } |
| |
| void primitiveTypes() { |
| // As argument to a function. |
| for (int I = 0; I < N; ++I) { |
| copyArg(Ints[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| // CHECK-FIXES-NEXT: copyArg(Int); |
| for (int I = 0; I < N; ++I) { |
| constRefArg(Ints[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| // CHECK-FIXES-NEXT: constRefArg(Int); |
| for (int I = 0; I < N; ++I) { |
| nonConstRefArg(Ints[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int & Int : Ints) |
| // CHECK-FIXES-NEXT: nonConstRefArg(Int); |
| |
| // Builtin operators. |
| // Comparisons. |
| for (int I = 0; I < N; ++I) { |
| if (Ints[I] < N) |
| foo(); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| // CHECK-FIXES-NEXT: if (Int < N) |
| |
| for (int I = 0; I < N; ++I) { |
| if (N == Ints[I]) |
| foo(); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| // CHECK-FIXES-NEXT: if (N == Int) |
| |
| // Assignment. |
| for (int I = 0; I < N; ++I) { |
| Ints[I] = OtherInt; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int & Int : Ints) |
| // CHECK-FIXES-NEXT: Int = OtherInt; |
| |
| for (int I = 0; I < N; ++I) { |
| OtherInt = Ints[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| // CHECK-FIXES-NEXT: OtherInt = Int; |
| |
| for (int I = 0; I < N; ++I) { |
| OtherInt = Ints[I] = OtherInt; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int & Int : Ints) |
| // CHECK-FIXES-NEXT: OtherInt = Int = OtherInt; |
| |
| // Arithmetic operations. |
| for (int I = 0; I < N; ++I) { |
| OtherInt += Ints[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| // CHECK-FIXES-NEXT: OtherInt += Int; |
| |
| for (int I = 0; I < N; ++I) { |
| Ints[I] += Ints[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int & Int : Ints) |
| // CHECK-FIXES-NEXT: Int += Int; |
| |
| for (int I = 0; I < N; ++I) { |
| int Res = 5 * (Ints[I] + 1) - Ints[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| // CHECK-FIXES-NEXT: int Res = 5 * (Int + 1) - Int; |
| } |
| |
| void takingReferences() { |
| // We do it twice to prevent the check from thinking that they are aliases. |
| |
| // Class type. |
| for (int I = 0; I < N; ++I) { |
| Str &J = Array[I]; |
| Str &K = Array[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & I : Array) |
| // CHECK-FIXES-NEXT: Str &J = I; |
| // CHECK-FIXES-NEXT: Str &K = I; |
| for (int I = 0; I < N; ++I) { |
| const Str &J = Array[I]; |
| const Str &K = Array[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto I : Array) |
| // CHECK-FIXES-NEXT: const Str &J = I; |
| // CHECK-FIXES-NEXT: const Str &K = I; |
| |
| // Primitive type. |
| for (int I = 0; I < N; ++I) { |
| int &J = Ints[I]; |
| int &K = Ints[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int & Int : Ints) |
| // CHECK-FIXES-NEXT: int &J = Int; |
| // CHECK-FIXES-NEXT: int &K = Int; |
| for (int I = 0; I < N; ++I) { |
| const int &J = Ints[I]; |
| const int &K = Ints[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| // CHECK-FIXES-NEXT: const int &J = Int; |
| // CHECK-FIXES-NEXT: const int &K = Int; |
| |
| // Aliases. |
| for (int I = 0; I < N; ++I) { |
| const Str &J = Array[I]; |
| (void)J; |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto J : Array) |
| for (int I = 0; I < N; ++I) { |
| Str &J = Array[I]; |
| (void)J; |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto & J : Array) |
| |
| for (int I = 0; I < N; ++I) { |
| const int &J = Ints[I]; |
| (void)J; |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int J : Ints) |
| |
| for (int I = 0; I < N; ++I) { |
| int &J = Ints[I]; |
| (void)J; |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int & J : Ints) |
| } |
| |
| template <class T> |
| struct vector { |
| unsigned size() const; |
| const T &operator[](int) const; |
| T &operator[](int); |
| T *begin(); |
| T *end(); |
| const T *begin() const; |
| const T *end() const; |
| }; |
| |
| // If the elements are already constant, we won't do any ImplicitCast to const. |
| void testContainerOfConstIents() { |
| const int Ints[N]{}; |
| for (int I = 0; I < N; ++I) { |
| OtherInt -= Ints[I]; |
| } |
| // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| |
| vector<const Str> Strs; |
| for (int I = 0; I < Strs.size(); ++I) { |
| Strs[I].constMember(0); |
| constRefArg(Strs[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
| // CHECK-FIXES: for (auto Str : Strs) |
| } |
| |
| // When we are inside a const-qualified member functions, all the data members |
| // are implicitly set as const. As before, there won't be any ImplicitCast to |
| // const in their usages. |
| class TestInsideConstFunction { |
| const static int N = 10; |
| int Ints[N]; |
| Str Array[N]; |
| vector<int> V; |
| |
| void foo() const { |
| for (int I = 0; I < N; ++I) { |
| if (Ints[I]) |
| copyArg(Ints[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop |
| // CHECK-FIXES: for (int Int : Ints) |
| |
| for (int I = 0; I < N; ++I) { |
| Array[I].constMember(0); |
| constRefArg(Array[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop |
| // CHECK-FIXES: for (auto I : Array) |
| |
| for (int I = 0; I < V.size(); ++I) { |
| if (V[I]) |
| copyArg(V[I]); |
| } |
| // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop |
| // CHECK-FIXES: for (int I : V) |
| } |
| }; |