Summary: I recently found that the variable naming wasn't working as expected with containers that are data members. The new index always received the name "Elem" (or equivalent) regardless of the container's name. The check was assuming that the container's declaration was a VarDecl, which cannot be converted to a FieldDecl (a data member), and then it could never retrieve its name. This also fixes some cases where the check failed to find the container at all (so it didn't do any fix) because of the same reason. Reviewers: klimek Subscribers: cfe-commits, alexfh Differential Revision: http://reviews.llvm.org/D14289 llvm-svn: 251943
486 lines
10 KiB
C++
486 lines
10 KiB
C++
// RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -std=c++11 -I %S/Inputs/modernize-loop-convert
|
|
|
|
#include "structures.h"
|
|
|
|
// CHECK-FIXES-NOT: for ({{.*[^:]:[^:].*}})
|
|
// CHECK-MESSAGES-NOT: modernize-loop-convert
|
|
|
|
namespace Negative {
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
namespace NegativeIterator {
|
|
|
|
S Ss;
|
|
T Tt;
|
|
U Tu;
|
|
|
|
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 = Tt.begin(), E = Tt.end(), F = E; I != E; ++I)
|
|
int K = *I;
|
|
|
|
for (T::iterator I = Tt.begin(), E = Tt.end(); I != E;)
|
|
int K = *I;
|
|
|
|
for (T::iterator I = Tt.begin(), E = Tt.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 = Tt.begin(), E = Tt.end(); Lower < N; ++I)
|
|
int K = *I;
|
|
|
|
for (T::iterator I = Tt.begin(), E = Tt.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(Tt.begin(), 0), E = Tt.end();
|
|
I != E; ++I)
|
|
int K = *I;
|
|
for (T::iterator I = ExtraConstructor(Tt.begin()), E = Tt.end(); I != E; ++I)
|
|
int K = *I;
|
|
}
|
|
|
|
void foo(S::iterator It) {}
|
|
class Foo {public: void bar(S::iterator It); };
|
|
Foo Fo;
|
|
|
|
void iteratorUsed() {
|
|
for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
|
|
foo(I);
|
|
|
|
for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
|
|
Fo.bar(I);
|
|
|
|
S::iterator Ret;
|
|
for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
|
|
Ret = I;
|
|
}
|
|
|
|
void iteratorMemberUsed() {
|
|
for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
|
|
I.X = *I;
|
|
|
|
for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
|
|
int K = I.X + *I;
|
|
|
|
for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
|
|
int K = E.X + *I;
|
|
}
|
|
|
|
void iteratorMethodCalled() {
|
|
for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
|
|
I.insert(3);
|
|
|
|
for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
|
|
if (I != I)
|
|
int K = 3;
|
|
}
|
|
|
|
void iteratorOperatorCalled() {
|
|
for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
|
|
int K = *(++I);
|
|
|
|
for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
|
|
MutableVal K = *(++I);
|
|
}
|
|
|
|
void differentContainers() {
|
|
T Other;
|
|
for (T::iterator I = Tt.begin(), E = Other.end(); I != E; ++I)
|
|
int K = *I;
|
|
|
|
for (T::iterator I = Other.begin(), E = Tt.end(); I != E; ++I)
|
|
int K = *I;
|
|
|
|
S OtherS;
|
|
for (S::iterator I = Ss.begin(), E = OtherS.end(); I != E; ++I)
|
|
MutableVal K = *I;
|
|
|
|
for (S::iterator I = OtherS.begin(), E = Ss.end(); I != E; ++I)
|
|
MutableVal K = *I;
|
|
}
|
|
|
|
void wrongIterators() {
|
|
T::iterator Other;
|
|
for (T::iterator I = Tt.begin(), E = Tt.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 = Tt.begin(), E = Tt.end(); I != E; ++I)
|
|
f(I, *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 = Tt.end();
|
|
for (T::iterator I = Tt.begin(); I != TheEnd; ++I)
|
|
int K = *I;
|
|
|
|
T::iterator TheBegin = Tt.begin();
|
|
for (T::iterator E = Tt.end(); TheBegin != E; ++TheBegin)
|
|
int K = *TheBegin;
|
|
}
|
|
|
|
} // namespace NegativeIterator
|
|
|
|
namespace NegativePseudoArray {
|
|
|
|
const int N = 6;
|
|
dependent<int> V;
|
|
dependent<int> *Pv;
|
|
|
|
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];
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
} // namespace NegativePseudoArray
|
|
|
|
namespace NegativeMultiEndCall {
|
|
|
|
S Ss;
|
|
T Tt;
|
|
U Uu;
|
|
|
|
void f(X);
|
|
void f(S);
|
|
void f(T);
|
|
|
|
void complexContainer() {
|
|
X Xx;
|
|
for (S::iterator I = Xx.Ss.begin(), E = Xx.Ss.end(); I != E; ++I) {
|
|
f(Xx);
|
|
MutableVal K = *I;
|
|
}
|
|
|
|
for (T::iterator I = Xx.Tt.begin(), E = Xx.Tt.end(); I != E; ++I) {
|
|
f(Xx);
|
|
int K = *I;
|
|
}
|
|
|
|
for (S::iterator I = Xx.Ss.begin(), E = Xx.Ss.end(); I != E; ++I) {
|
|
f(Xx.Ss);
|
|
MutableVal K = *I;
|
|
}
|
|
|
|
for (T::iterator I = Xx.Tt.begin(), E = Xx.Tt.end(); I != E; ++I) {
|
|
f(Xx.Tt);
|
|
int K = *I;
|
|
}
|
|
|
|
for (S::iterator I = Xx.getS().begin(), E = Xx.getS().end(); I != E; ++I) {
|
|
f(Xx.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;
|
|
}
|
|
}
|
|
|
|
} // namespace NegativeMultiEndCall
|
|
|
|
namespace NoUsages {
|
|
|
|
const int N = 6;
|
|
int Arr[N] = {1, 2, 3, 4, 5, 6};
|
|
S Ss;
|
|
dependent<int> V;
|
|
int Count = 0;
|
|
|
|
void foo();
|
|
|
|
void f() {
|
|
for (int I = 0; I < N; ++I) {}
|
|
for (int I = 0; I < N; ++I)
|
|
printf("Hello world\n");
|
|
for (int I = 0; I < N; ++I)
|
|
++Count;
|
|
for (int I = 0; I < N; ++I)
|
|
foo();
|
|
|
|
for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I) {}
|
|
for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
|
|
printf("Hello world\n");
|
|
for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
|
|
++Count;
|
|
for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
|
|
foo();
|
|
|
|
for (int I = 0; I < V.size(); ++I) {}
|
|
for (int I = 0; I < V.size(); ++I)
|
|
printf("Hello world\n");
|
|
for (int I = 0; I < V.size(); ++I)
|
|
++Count;
|
|
for (int I = 0; I < V.size(); ++I)
|
|
foo();
|
|
}
|
|
|
|
} // namespace NoUsages
|