Skip to content

Commit e984d11

Browse files
authored
[clang-tidy] loop convert can handle lambda init capture (#109159)
Fixes: #109083 Current implement ignore the whole lambda capture. This patch wants to do traverse for capture init expr also
1 parent eb4a91d commit e984d11

File tree

4 files changed

+48
-10
lines changed

4 files changed

+48
-10
lines changed

clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
777777
const LambdaCapture *C,
778778
Expr *Init) {
779779
if (C->capturesVariable()) {
780-
const ValueDecl *VDecl = C->getCapturedVar();
780+
ValueDecl *VDecl = C->getCapturedVar();
781781
if (areSameVariable(IndexVar, VDecl)) {
782782
// FIXME: if the index is captured, it will count as an usage and the
783783
// alias (if any) won't work, because it is only used in case of having
@@ -787,6 +787,8 @@ bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
787787
: Usage::UK_CaptureByRef,
788788
C->getLocation()));
789789
}
790+
if (VDecl->isInitCapture())
791+
TraverseStmtImpl(cast<VarDecl>(VDecl)->getInit());
790792
}
791793
return VisitorBase::TraverseLambdaCapture(LE, C, Init);
792794
}
@@ -816,6 +818,17 @@ bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt *S) {
816818
return true;
817819
}
818820

821+
bool ForLoopIndexUseVisitor::TraverseStmtImpl(Stmt *S) {
822+
// All this pointer swapping is a mechanism for tracking immediate parentage
823+
// of Stmts.
824+
const Stmt *OldNextParent = NextStmtParent;
825+
CurrStmtParent = NextStmtParent;
826+
NextStmtParent = S;
827+
bool Result = VisitorBase::TraverseStmt(S);
828+
NextStmtParent = OldNextParent;
829+
return Result;
830+
}
831+
819832
bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
820833
// If this is an initialization expression for a lambda capture, prune the
821834
// traversal so that we don't end up diagnosing the contained DeclRefExpr as
@@ -828,15 +841,7 @@ bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
828841
return true;
829842
}
830843
}
831-
832-
// All this pointer swapping is a mechanism for tracking immediate parentage
833-
// of Stmts.
834-
const Stmt *OldNextParent = NextStmtParent;
835-
CurrStmtParent = NextStmtParent;
836-
NextStmtParent = S;
837-
bool Result = VisitorBase::TraverseStmt(S);
838-
NextStmtParent = OldNextParent;
839-
return Result;
844+
return TraverseStmtImpl(S);
840845
}
841846

842847
std::string VariableNamer::createIndexName() {

clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ class ForLoopIndexUseVisitor
354354
bool VisitDeclStmt(DeclStmt *S);
355355
bool TraverseStmt(Stmt *S);
356356

357+
bool TraverseStmtImpl(Stmt *S);
358+
357359
/// Add an expression to the list of expressions on which the container
358360
/// expression depends.
359361
void addComponent(const Expr *E);

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ Changes in existing checks
171171
as a replacement for parameters of incomplete C array type in C++20 and
172172
``std::array`` or ``std::vector`` before C++20.
173173

174+
- Improved :doc:`modernize-loop-convert
175+
<clang-tidy/checks/modernize/loop-convert>` check to fix false positive when
176+
using loop variable in initializer of lambda capture.
177+
174178
- Improved :doc:`modernize-min-max-use-initializer-list
175179
<clang-tidy/checks/modernize/min-max-use-initializer-list>` check by fixing
176180
a false positive when only an implicit conversion happened inside an

clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-basic.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,3 +980,30 @@ namespace PR78381 {
980980
}
981981
}
982982
}
983+
984+
namespace GH109083 {
985+
void test() {
986+
const int N = 6;
987+
int Arr[N] = {1, 2, 3, 4, 5, 6};
988+
989+
for (int I = 0; I < N; ++I) {
990+
auto V = [T = Arr[I]]() {};
991+
}
992+
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
993+
// CHECK-FIXES: for (int I : Arr)
994+
// CHECK-FIXES-NEXT: auto V = [T = I]() {};
995+
for (int I = 0; I < N; ++I) {
996+
auto V = [T = 10 + Arr[I]]() {};
997+
}
998+
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
999+
// CHECK-FIXES: for (int I : Arr)
1000+
// CHECK-FIXES-NEXT: auto V = [T = 10 + I]() {};
1001+
1002+
for (int I = 0; I < N; ++I) {
1003+
auto V = [T = I]() {};
1004+
}
1005+
for (int I = 0; I < N; ++I) {
1006+
auto V = [T = I + 10]() {};
1007+
}
1008+
}
1009+
} // namespace GH109083

0 commit comments

Comments
 (0)