[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/vbvictor closed https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
flovent wrote: > LGTM. I tried to address the specific case of tuple structured bindings in my > PR: #147410. Your PR handles the case for all structured bindings. It may be > a good idea to add tests for tuple (you can lift from my PR) and array > structured bindings too. Thanks for the review and advice, these testcases have now been added. https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/flovent edited https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/flovent updated
https://github.com/llvm/llvm-project/pull/144213
>From 69d64b55d34b84a316cf4674b304f5535d9aa9d4 Mon Sep 17 00:00:00 2001
From: flovent
Date: Sat, 14 Jun 2025 15:52:26 +0800
Subject: [PATCH 1/5] [clang-tidy] Improve `bugprone-infinite-loop` check by
adding handing for strucuted bindings
---
.../clang-tidy/bugprone/InfiniteLoopCheck.cpp | 33 +++-
.../clang-tidy/utils/Aliasing.cpp | 14 ++--
clang-tools-extra/clang-tidy/utils/Aliasing.h | 2 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 +
.../checkers/bugprone/infinite-loop.cpp | 81 +++
5 files changed, 124 insertions(+), 10 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index 3c3024d538785..951d67ab5c21a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -49,7 +49,7 @@ static Matcher loopEndingStmt(Matcher Internal) {
}
/// Return whether `Var` was changed in `LoopStmt`.
-static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var,
+static bool isChanged(const Stmt *LoopStmt, const ValueDecl *Var,
ASTContext *Context) {
if (const auto *ForLoop = dyn_cast(LoopStmt))
return (ForLoop->getInc() &&
@@ -82,6 +82,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
{
+if (!DD->isLocalVarDeclOrParm())
+ return true;
+
+if (DD->getType().isVolatileQualified())
+ return true;
+
+if (!BD->getType().getTypePtr()->isIntegerType())
+ return true;
+
+return hasPtrOrReferenceInFunc(Func, BD) ||
+ isChanged(LoopStmt, BD, Context);
+ }
+}
} else if (isa(Cond)) {
// FIXME: Handle MemberExpr.
@@ -123,6 +140,10 @@ static std::string getCondVarNames(const Stmt *Cond) {
if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *Var = dyn_cast(DRE->getDecl()))
return std::string(Var->getName());
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ return std::string(BD->getName());
+}
}
std::string Result;
@@ -214,10 +235,18 @@ static bool overlap(ArrayRef SCC,
/// returns true iff `Cond` involves at least one static local variable.
static bool hasStaticLocalVariable(const Stmt *Cond) {
- if (const auto *DRE = dyn_cast(Cond))
+ if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *VD = dyn_cast(DRE->getDecl()))
if (VD->isStaticLocal())
return true;
+
+if (const auto *BD = dyn_cast(DRE->getDecl()))
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
+if (DD->isStaticLocal())
+ return true;
+ }
+
for (const Stmt *Child : Cond->children())
if (Child && hasStaticLocalVariable(Child))
return true;
diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
index 2facf0625605e..cbe4873b5c022 100644
--- a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
+++ b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
@@ -14,14 +14,14 @@
namespace clang::tidy::utils {
/// Return whether \p S is a reference to the declaration of \p Var.
-static bool isAccessForVar(const Stmt *S, const VarDecl *Var) {
+static bool isAccessForVar(const Stmt *S, const ValueDecl *Var) {
if (const auto *DRE = dyn_cast(S))
return DRE->getDecl() == Var;
return false;
}
-static bool capturesByRef(const CXXRecordDecl *RD, const VarDecl *Var) {
+static bool capturesByRef(const CXXRecordDecl *RD, const ValueDecl *Var) {
return llvm::any_of(RD->captures(), [Var](const LambdaCapture &C) {
return C.capturesVariable() && C.getCaptureKind() == LCK_ByRef &&
C.getCapturedVar() == Var;
@@ -29,9 +29,9 @@ static bool capturesByRef(const CXXRecordDecl *RD, const
VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) {
+static bool isPtrOrReferenceForVar(const Stmt *S, const ValueDecl *Var) {
// Treat block capture by reference as a form of taking a reference.
- if (Var->isEscapingByref())
+ if (const auto *VD = dyn_cast(Var); VD && VD->isEscapingByref())
return true;
if (const auto *DS = dyn_cast(S)) {
@@ -61,7 +61,7 @@ static bool isPtrOrReferenceForVar(const Stmt *S, const
VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) {
+static bool hasPtrOrReferenceInStmt(const Stmt *S, const ValueDecl *Var) {
if (isPtrOrReferenceFor
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
@@ -83,6 +83,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast(BD->getDecomposedDecl())) {
+if (!DD->isLocalVarDeclOrParm())
+ return true;
+
+if (DD->getType().isVolatileQualified())
+ return true;
+
+if (!BD->getType().getTypePtr()->isIntegerType())
+ return true;
+
+return hasPtrOrReferenceInFunc(Func, BD) ||
+ isChanged(LoopStmt, BD, Context);
flovent wrote:
Done in
[87a68f7](https://github.com/llvm/llvm-project/pull/144213/commits/87a68f7ca9144f05eb37a51abc537af2fcb53fb2)
https://github.com/llvm/llvm-project/pull/144213
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/flovent updated
https://github.com/llvm/llvm-project/pull/144213
>From 6fce04d8484a3600f292a8bbdd8621db25be7f1d Mon Sep 17 00:00:00 2001
From: flovent
Date: Sat, 14 Jun 2025 15:52:26 +0800
Subject: [PATCH 1/4] [clang-tidy] Improve `bugprone-infinite-loop` check by
adding handing for strucuted bindings
---
.../clang-tidy/bugprone/InfiniteLoopCheck.cpp | 33 +++-
.../clang-tidy/utils/Aliasing.cpp | 14 ++--
clang-tools-extra/clang-tidy/utils/Aliasing.h | 2 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 +
.../checkers/bugprone/infinite-loop.cpp | 81 +++
5 files changed, 124 insertions(+), 10 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index 3c3024d538785..951d67ab5c21a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -49,7 +49,7 @@ static Matcher loopEndingStmt(Matcher Internal) {
}
/// Return whether `Var` was changed in `LoopStmt`.
-static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var,
+static bool isChanged(const Stmt *LoopStmt, const ValueDecl *Var,
ASTContext *Context) {
if (const auto *ForLoop = dyn_cast(LoopStmt))
return (ForLoop->getInc() &&
@@ -82,6 +82,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
{
+if (!DD->isLocalVarDeclOrParm())
+ return true;
+
+if (DD->getType().isVolatileQualified())
+ return true;
+
+if (!BD->getType().getTypePtr()->isIntegerType())
+ return true;
+
+return hasPtrOrReferenceInFunc(Func, BD) ||
+ isChanged(LoopStmt, BD, Context);
+ }
+}
} else if (isa(Cond)) {
// FIXME: Handle MemberExpr.
@@ -123,6 +140,10 @@ static std::string getCondVarNames(const Stmt *Cond) {
if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *Var = dyn_cast(DRE->getDecl()))
return std::string(Var->getName());
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ return std::string(BD->getName());
+}
}
std::string Result;
@@ -214,10 +235,18 @@ static bool overlap(ArrayRef SCC,
/// returns true iff `Cond` involves at least one static local variable.
static bool hasStaticLocalVariable(const Stmt *Cond) {
- if (const auto *DRE = dyn_cast(Cond))
+ if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *VD = dyn_cast(DRE->getDecl()))
if (VD->isStaticLocal())
return true;
+
+if (const auto *BD = dyn_cast(DRE->getDecl()))
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
+if (DD->isStaticLocal())
+ return true;
+ }
+
for (const Stmt *Child : Cond->children())
if (Child && hasStaticLocalVariable(Child))
return true;
diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
index 2facf0625605e..cbe4873b5c022 100644
--- a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
+++ b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
@@ -14,14 +14,14 @@
namespace clang::tidy::utils {
/// Return whether \p S is a reference to the declaration of \p Var.
-static bool isAccessForVar(const Stmt *S, const VarDecl *Var) {
+static bool isAccessForVar(const Stmt *S, const ValueDecl *Var) {
if (const auto *DRE = dyn_cast(S))
return DRE->getDecl() == Var;
return false;
}
-static bool capturesByRef(const CXXRecordDecl *RD, const VarDecl *Var) {
+static bool capturesByRef(const CXXRecordDecl *RD, const ValueDecl *Var) {
return llvm::any_of(RD->captures(), [Var](const LambdaCapture &C) {
return C.capturesVariable() && C.getCaptureKind() == LCK_ByRef &&
C.getCapturedVar() == Var;
@@ -29,9 +29,9 @@ static bool capturesByRef(const CXXRecordDecl *RD, const
VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) {
+static bool isPtrOrReferenceForVar(const Stmt *S, const ValueDecl *Var) {
// Treat block capture by reference as a form of taking a reference.
- if (Var->isEscapingByref())
+ if (const auto *VD = dyn_cast(Var); VD && VD->isEscapingByref())
return true;
if (const auto *DS = dyn_cast(S)) {
@@ -61,7 +61,7 @@ static bool isPtrOrReferenceForVar(const Stmt *S, const
VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) {
+static bool hasPtrOrReferenceInStmt(const Stmt *S, const ValueDecl *Var) {
if (isPtrOrReferenceFor
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/carlosgalvezp approved this pull request. LGTM, but please rebase onto latest trunk and address/resolve pending comments. https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
@@ -83,6 +83,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast(BD->getDecomposedDecl())) {
+if (!DD->isLocalVarDeclOrParm())
+ return true;
+
+if (DD->getType().isVolatileQualified())
+ return true;
+
+if (!BD->getType().getTypePtr()->isIntegerType())
+ return true;
+
+return hasPtrOrReferenceInFunc(Func, BD) ||
+ isChanged(LoopStmt, BD, Context);
HerrCai0907 wrote:
avoid duplicated code with `VarDecl` part. extract them to separated function
https://github.com/llvm/llvm-project/pull/144213
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/HerrCai0907 approved this pull request. LGTM except nit https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/HerrCai0907 edited https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/vbvictor approved this pull request. LGTM, but I'd like to wait for a second reviewer for some time to double-check if some tests are missing https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/flovent updated
https://github.com/llvm/llvm-project/pull/144213
>From 87e03841749296dbdf3e93cc3655a8a48c793da9 Mon Sep 17 00:00:00 2001
From: flovent
Date: Sat, 14 Jun 2025 15:52:26 +0800
Subject: [PATCH 1/3] [clang-tidy] Improve `bugprone-infinite-loop` check by
adding handing for strucuted bindings
---
.../clang-tidy/bugprone/InfiniteLoopCheck.cpp | 33 +++-
.../clang-tidy/utils/Aliasing.cpp | 14 ++--
clang-tools-extra/clang-tidy/utils/Aliasing.h | 2 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 +
.../checkers/bugprone/infinite-loop.cpp | 81 +++
5 files changed, 124 insertions(+), 10 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index 07116a7ff15f5..4ceca53e2f7f3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -50,7 +50,7 @@ static Matcher loopEndingStmt(Matcher Internal) {
}
/// Return whether `Var` was changed in `LoopStmt`.
-static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var,
+static bool isChanged(const Stmt *LoopStmt, const ValueDecl *Var,
ASTContext *Context) {
if (const auto *ForLoop = dyn_cast(LoopStmt))
return (ForLoop->getInc() &&
@@ -83,6 +83,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
{
+if (!DD->isLocalVarDeclOrParm())
+ return true;
+
+if (DD->getType().isVolatileQualified())
+ return true;
+
+if (!BD->getType().getTypePtr()->isIntegerType())
+ return true;
+
+return hasPtrOrReferenceInFunc(Func, BD) ||
+ isChanged(LoopStmt, BD, Context);
+ }
+}
} else if (isa(Cond)) {
// FIXME: Handle MemberExpr.
@@ -124,6 +141,10 @@ static std::string getCondVarNames(const Stmt *Cond) {
if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *Var = dyn_cast(DRE->getDecl()))
return std::string(Var->getName());
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ return std::string(BD->getName());
+}
}
std::string Result;
@@ -215,10 +236,18 @@ static bool overlap(ArrayRef SCC,
/// returns true iff `Cond` involves at least one static local variable.
static bool hasStaticLocalVariable(const Stmt *Cond) {
- if (const auto *DRE = dyn_cast(Cond))
+ if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *VD = dyn_cast(DRE->getDecl()))
if (VD->isStaticLocal())
return true;
+
+if (const auto *BD = dyn_cast(DRE->getDecl()))
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
+if (DD->isStaticLocal())
+ return true;
+ }
+
for (const Stmt *Child : Cond->children())
if (Child && hasStaticLocalVariable(Child))
return true;
diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
index 2facf0625605e..cbe4873b5c022 100644
--- a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
+++ b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
@@ -14,14 +14,14 @@
namespace clang::tidy::utils {
/// Return whether \p S is a reference to the declaration of \p Var.
-static bool isAccessForVar(const Stmt *S, const VarDecl *Var) {
+static bool isAccessForVar(const Stmt *S, const ValueDecl *Var) {
if (const auto *DRE = dyn_cast(S))
return DRE->getDecl() == Var;
return false;
}
-static bool capturesByRef(const CXXRecordDecl *RD, const VarDecl *Var) {
+static bool capturesByRef(const CXXRecordDecl *RD, const ValueDecl *Var) {
return llvm::any_of(RD->captures(), [Var](const LambdaCapture &C) {
return C.capturesVariable() && C.getCaptureKind() == LCK_ByRef &&
C.getCapturedVar() == Var;
@@ -29,9 +29,9 @@ static bool capturesByRef(const CXXRecordDecl *RD, const
VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) {
+static bool isPtrOrReferenceForVar(const Stmt *S, const ValueDecl *Var) {
// Treat block capture by reference as a form of taking a reference.
- if (Var->isEscapingByref())
+ if (const auto *VD = dyn_cast(Var); VD && VD->isEscapingByref())
return true;
if (const auto *DS = dyn_cast(S)) {
@@ -61,7 +61,7 @@ static bool isPtrOrReferenceForVar(const Stmt *S, const
VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) {
+static bool hasPtrOrReferenceInStmt(const Stmt *S, const ValueDecl *Var) {
if (isPtrOrReferenceFor
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
flovent wrote: ping. https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/flovent deleted https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
flovent wrote: New CI failure seems unrelated to the new commit. https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
@@ -83,6 +83,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
{
flovent wrote:
But does `BindingDecl::getDecomposedDecl` always return non null value? I find
the use of this API in clang, `ValueDecl::getPotentiallyDecomposedVarDecl` does
check it nullability,
```
VarDecl *ValueDecl::getPotentiallyDecomposedVarDecl() {
// ...
if (auto *BD = llvm::dyn_cast(this))
return llvm::dyn_cast_if_present(BD->getDecomposedDecl());
return nullptr;
}
```
https://github.com/llvm/llvm-project/pull/144213
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
@@ -83,6 +83,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
{
flovent wrote:
You are right, null check should not be necessary here, updated.
https://github.com/llvm/llvm-project/pull/144213
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/flovent updated
https://github.com/llvm/llvm-project/pull/144213
>From 87e03841749296dbdf3e93cc3655a8a48c793da9 Mon Sep 17 00:00:00 2001
From: flovent
Date: Sat, 14 Jun 2025 15:52:26 +0800
Subject: [PATCH 1/2] [clang-tidy] Improve `bugprone-infinite-loop` check by
adding handing for strucuted bindings
---
.../clang-tidy/bugprone/InfiniteLoopCheck.cpp | 33 +++-
.../clang-tidy/utils/Aliasing.cpp | 14 ++--
clang-tools-extra/clang-tidy/utils/Aliasing.h | 2 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 +
.../checkers/bugprone/infinite-loop.cpp | 81 +++
5 files changed, 124 insertions(+), 10 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index 07116a7ff15f5..4ceca53e2f7f3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -50,7 +50,7 @@ static Matcher loopEndingStmt(Matcher Internal) {
}
/// Return whether `Var` was changed in `LoopStmt`.
-static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var,
+static bool isChanged(const Stmt *LoopStmt, const ValueDecl *Var,
ASTContext *Context) {
if (const auto *ForLoop = dyn_cast(LoopStmt))
return (ForLoop->getInc() &&
@@ -83,6 +83,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
{
+if (!DD->isLocalVarDeclOrParm())
+ return true;
+
+if (DD->getType().isVolatileQualified())
+ return true;
+
+if (!BD->getType().getTypePtr()->isIntegerType())
+ return true;
+
+return hasPtrOrReferenceInFunc(Func, BD) ||
+ isChanged(LoopStmt, BD, Context);
+ }
+}
} else if (isa(Cond)) {
// FIXME: Handle MemberExpr.
@@ -124,6 +141,10 @@ static std::string getCondVarNames(const Stmt *Cond) {
if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *Var = dyn_cast(DRE->getDecl()))
return std::string(Var->getName());
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ return std::string(BD->getName());
+}
}
std::string Result;
@@ -215,10 +236,18 @@ static bool overlap(ArrayRef SCC,
/// returns true iff `Cond` involves at least one static local variable.
static bool hasStaticLocalVariable(const Stmt *Cond) {
- if (const auto *DRE = dyn_cast(Cond))
+ if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *VD = dyn_cast(DRE->getDecl()))
if (VD->isStaticLocal())
return true;
+
+if (const auto *BD = dyn_cast(DRE->getDecl()))
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
+if (DD->isStaticLocal())
+ return true;
+ }
+
for (const Stmt *Child : Cond->children())
if (Child && hasStaticLocalVariable(Child))
return true;
diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
index 2facf0625605e..cbe4873b5c022 100644
--- a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
+++ b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
@@ -14,14 +14,14 @@
namespace clang::tidy::utils {
/// Return whether \p S is a reference to the declaration of \p Var.
-static bool isAccessForVar(const Stmt *S, const VarDecl *Var) {
+static bool isAccessForVar(const Stmt *S, const ValueDecl *Var) {
if (const auto *DRE = dyn_cast(S))
return DRE->getDecl() == Var;
return false;
}
-static bool capturesByRef(const CXXRecordDecl *RD, const VarDecl *Var) {
+static bool capturesByRef(const CXXRecordDecl *RD, const ValueDecl *Var) {
return llvm::any_of(RD->captures(), [Var](const LambdaCapture &C) {
return C.capturesVariable() && C.getCaptureKind() == LCK_ByRef &&
C.getCapturedVar() == Var;
@@ -29,9 +29,9 @@ static bool capturesByRef(const CXXRecordDecl *RD, const
VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) {
+static bool isPtrOrReferenceForVar(const Stmt *S, const ValueDecl *Var) {
// Treat block capture by reference as a form of taking a reference.
- if (Var->isEscapingByref())
+ if (const auto *VD = dyn_cast(Var); VD && VD->isEscapingByref())
return true;
if (const auto *DS = dyn_cast(S)) {
@@ -61,7 +61,7 @@ static bool isPtrOrReferenceForVar(const Stmt *S, const
VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) {
+static bool hasPtrOrReferenceInStmt(const Stmt *S, const ValueDecl *Var) {
if (isPtrOrReferenceFor
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
@@ -215,10 +236,18 @@ static bool overlap(ArrayRef SCC,
/// returns true iff `Cond` involves at least one static local variable.
static bool hasStaticLocalVariable(const Stmt *Cond) {
- if (const auto *DRE = dyn_cast(Cond))
+ if (const auto *DRE = dyn_cast(Cond)) {
if (const auto *VD = dyn_cast(DRE->getDecl()))
if (VD->isStaticLocal())
return true;
+
+if (const auto *BD = dyn_cast(DRE->getDecl()))
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
vbvictor wrote:
same with `dyn_cast_if_present` here
https://github.com/llvm/llvm-project/pull/144213
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
@@ -83,6 +83,23 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func,
const Stmt *LoopStmt,
isChanged(LoopStmt, Var, Context);
// FIXME: Track references.
}
+
+if (const auto *BD = dyn_cast(DRE->getDecl())) {
+ if (const auto *DD =
+ dyn_cast_if_present(BD->getDecomposedDecl()))
{
vbvictor wrote:
What is the profit of using `dyn_cast_if_present` here?
`DecompositionDecl` may or may not be there, but the same rules apply to
previous cast: `BindingDecl` also may or not be there.
https://github.com/llvm/llvm-project/pull/144213
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Improve `bugprone-infinite-loop` check by adding handing for structured bindings (PR #144213)
https://github.com/flovent edited https://github.com/llvm/llvm-project/pull/144213 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
