[clang-tidy] Extend LoopConvert on array with `!=` comparison

Enables transforming loops of the form:
```
for (int i = 0; I != container.size(); ++I) { container[I]...; }
for (int i = 0; I != N; ++I) { FixedArrSizeN[I]...; }
```

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D97940
This commit is contained in:
Nathan James 2021-03-04 18:58:42 +00:00
parent f2b749be15
commit a85eb11129
No known key found for this signature in database
GPG Key ID: CC007AFCDA90AA5F
2 changed files with 81 additions and 28 deletions

View File

@ -83,6 +83,17 @@ static const StatementMatcher incrementVarMatcher() {
return declRefExpr(to(varDecl(equalsBoundNode(InitVarName))));
}
static StatementMatcher
arrayConditionMatcher(internal::Matcher<Expr> LimitExpr) {
return binaryOperator(
anyOf(allOf(hasOperatorName("<"), hasLHS(integerComparisonMatcher()),
hasRHS(LimitExpr)),
allOf(hasOperatorName(">"), hasLHS(LimitExpr),
hasRHS(integerComparisonMatcher())),
allOf(hasOperatorName("!="),
hasOperands(integerComparisonMatcher(), LimitExpr))));
}
/// The matcher for loops over arrays.
/// \code
/// for (int i = 0; i < 3 + 2; ++i) { ... }
@ -99,18 +110,12 @@ StatementMatcher makeArrayLoopMatcher() {
StatementMatcher ArrayBoundMatcher =
expr(hasType(isInteger())).bind(ConditionBoundName);
return forStmt(
unless(isInTemplateInstantiation()),
hasLoopInit(declStmt(hasSingleDecl(initToZeroMatcher()))),
hasCondition(anyOf(
binaryOperator(hasOperatorName("<"),
hasLHS(integerComparisonMatcher()),
hasRHS(ArrayBoundMatcher)),
binaryOperator(hasOperatorName(">"), hasLHS(ArrayBoundMatcher),
hasRHS(integerComparisonMatcher())))),
hasIncrement(
unaryOperator(hasOperatorName("++"),
hasUnaryOperand(incrementVarMatcher()))))
return forStmt(unless(isInTemplateInstantiation()),
hasLoopInit(declStmt(hasSingleDecl(initToZeroMatcher()))),
hasCondition(arrayConditionMatcher(ArrayBoundMatcher)),
hasIncrement(
unaryOperator(hasOperatorName("++"),
hasUnaryOperand(incrementVarMatcher()))))
.bind(LoopNameArray);
}
@ -278,22 +283,16 @@ StatementMatcher makePseudoArrayLoopMatcher() {
declRefExpr(to(varDecl(equalsBoundNode(EndVarName))))),
EndInitMatcher));
return forStmt(
unless(isInTemplateInstantiation()),
hasLoopInit(
anyOf(declStmt(declCountIs(2),
containsDeclaration(0, initToZeroMatcher()),
containsDeclaration(1, EndDeclMatcher)),
declStmt(hasSingleDecl(initToZeroMatcher())))),
hasCondition(anyOf(
binaryOperator(hasOperatorName("<"),
hasLHS(integerComparisonMatcher()),
hasRHS(IndexBoundMatcher)),
binaryOperator(hasOperatorName(">"), hasLHS(IndexBoundMatcher),
hasRHS(integerComparisonMatcher())))),
hasIncrement(
unaryOperator(hasOperatorName("++"),
hasUnaryOperand(incrementVarMatcher()))))
return forStmt(unless(isInTemplateInstantiation()),
hasLoopInit(
anyOf(declStmt(declCountIs(2),
containsDeclaration(0, initToZeroMatcher()),
containsDeclaration(1, EndDeclMatcher)),
declStmt(hasSingleDecl(initToZeroMatcher())))),
hasCondition(arrayConditionMatcher(IndexBoundMatcher)),
hasIncrement(
unaryOperator(hasOperatorName("++"),
hasUnaryOperand(incrementVarMatcher()))))
.bind(LoopNamePseudoArray);
}

View File

@ -95,6 +95,33 @@ void f() {
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (auto & Tea : Teas)
// CHECK-FIXES-NEXT: Tea.g();
for (int I = 0; N > I; ++I) {
printf("Fibonacci number %d has address %p\n", Arr[I], &Arr[I]);
Sum += Arr[I] + 2;
}
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int & I : Arr)
// CHECK-FIXES-NEXT: printf("Fibonacci number %d has address %p\n", I, &I);
// CHECK-FIXES-NEXT: Sum += I + 2;
for (int I = 0; N != I; ++I) {
printf("Fibonacci number %d has address %p\n", Arr[I], &Arr[I]);
Sum += Arr[I] + 2;
}
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int & I : Arr)
// CHECK-FIXES-NEXT: printf("Fibonacci number %d has address %p\n", I, &I);
// CHECK-FIXES-NEXT: Sum += I + 2;
for (int I = 0; I != N; ++I) {
printf("Fibonacci number %d has address %p\n", Arr[I], &Arr[I]);
Sum += Arr[I] + 2;
}
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int & I : Arr)
// CHECK-FIXES-NEXT: printf("Fibonacci number %d has address %p\n", I, &I);
// CHECK-FIXES-NEXT: Sum += I + 2;
}
const int *constArray() {
@ -589,6 +616,33 @@ void f() {
// CHECK-FIXES: for (int I : *Cv)
// CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
// CHECK-FIXES-NEXT: Sum += I + 2;
for (int I = 0, E = V.size(); E > I; ++I) {
printf("Fibonacci number is %d\n", V[I]);
Sum += V[I] + 2;
}
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int I : V)
// CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
// CHECK-FIXES-NEXT: Sum += I + 2;
for (int I = 0, E = V.size(); I != E; ++I) {
printf("Fibonacci number is %d\n", V[I]);
Sum += V[I] + 2;
}
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int I : V)
// CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
// CHECK-FIXES-NEXT: Sum += I + 2;
for (int I = 0, E = V.size(); E != I; ++I) {
printf("Fibonacci number is %d\n", V[I]);
Sum += V[I] + 2;
}
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int I : V)
// CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
// CHECK-FIXES-NEXT: Sum += I + 2;
}
// Ensure that 'const auto &' is used with containers of non-trivial types.