https://github.com/qzhhhi created 
https://github.com/llvm/llvm-project/pull/204913

Prevent `readability-identifier-naming` from recursing indefinitely in 
dependent base lookup when `AggressiveDependentMemberLookup` maps a dependent 
template base back to the same record definition.

Track visited `CXXRecordDecl` definitions while walking base classes and stop 
revisiting the same definition. Add a regression test covering the dependent 
base cycle reproducer.

>From 729724741c21af552cc7a358d65ae0a1702ac740 Mon Sep 17 00:00:00 2001
From: qzhhhi <[email protected]>
Date: Sat, 20 Jun 2026 05:39:33 +0000
Subject: [PATCH] [clang-tidy] Guard `readability-identifier-naming` recursion
 in dependent base lookup

Prevent `readability-identifier-naming` from recursing indefinitely in 
dependent base lookup when `AggressiveDependentMemberLookup` maps a dependent 
template base back to the same record definition.

Track visited `CXXRecordDecl` definitions while walking base classes and stop 
revisiting the same definition. Add a regression test covering the dependent 
base cycle reproducer.
---
 .../utils/RenamerClangTidyCheck.cpp           | 21 +++++++++++++++----
 ...identifier-naming-dependent-base-cycle.cpp | 17 +++++++++++++++
 2 files changed, 34 insertions(+), 4 deletions(-)
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-dependent-base-cycle.cpp

diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp 
b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
index cb7ef19827675..d55c8f2e05c71 100644
--- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
@@ -17,6 +17,8 @@
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include <optional>
 
 #define DEBUG_TYPE "clang-tidy"
@@ -118,6 +120,8 @@ static const NamedDecl *getFailureForNamedDecl(const 
NamedDecl *ND) {
   return ND;
 }
 
+using RecursionProtectionSet = llvm::SmallPtrSet<const CXXRecordDecl *, 4>;
+
 /// Returns a decl matching the \p DeclName in \p Parent or one of its base
 /// classes. If \p AggressiveTemplateLookup is `true` then it will check
 /// template dependent base classes as well.
@@ -125,9 +129,17 @@ static const NamedDecl *getFailureForNamedDecl(const 
NamedDecl *ND) {
 /// flag indicating the multiple resolutions.
 static NameLookup findDeclInBases(const CXXRecordDecl &Parent,
                                   StringRef DeclName,
-                                  bool AggressiveTemplateLookup) {
+                                  bool AggressiveTemplateLookup,
+                                  RecursionProtectionSet &Visited) {
   if (!Parent.hasDefinition())
     return NameLookup(nullptr);
+
+  const auto *Definition = Parent.getDefinition();
+  if (!Visited.insert(Definition).second)
+    return NameLookup(nullptr);
+  auto RemoveFromVisited =
+      llvm::scope_exit([&Visited, Definition] { Visited.erase(Definition); });
+
   if (const NamedDecl *InClassRef = findDecl(Parent, DeclName))
     return NameLookup(InClassRef);
   const NamedDecl *Found = nullptr;
@@ -144,8 +156,8 @@ static NameLookup findDeclInBases(const CXXRecordDecl 
&Parent,
     }
     if (!Record)
       continue;
-    if (auto Search =
-            findDeclInBases(*Record, DeclName, AggressiveTemplateLookup)) {
+    if (auto Search = findDeclInBases(*Record, DeclName,
+                                      AggressiveTemplateLookup, Visited)) {
       if (*Search) {
         if (Found)
           return NameLookup(
@@ -301,8 +313,9 @@ class RenamerClangTidyVisitor
       return true;
     const StringRef DependentName = DeclName.getAsIdentifierInfo()->getName();
 
+    RecursionProtectionSet Visited;
     if (const NameLookup Resolved = findDeclInBases(
-            *Base, DependentName, AggressiveDependentMemberLookup)) {
+            *Base, DependentName, AggressiveDependentMemberLookup, Visited)) {
       if (*Resolved)
         Check->addUsage(*Resolved,
                         DepMemberRef->getMemberNameInfo().getSourceRange(), 
SM);
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-dependent-base-cycle.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-dependent-base-cycle.cpp
new file mode 100644
index 0000000000000..9dd966f92edf3
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-dependent-base-cycle.cpp
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s readability-identifier-naming %t -- \
+// RUN:   -config='{CheckOptions: { \
+// RUN:     readability-identifier-naming.AggressiveDependentMemberLookup: 
true \
+// RUN:   }}' -- -fno-delayed-template-parsing
+
+template <class T>
+struct A;
+
+template <class T>
+struct A<const T> {
+  int x;
+};
+
+template <class T>
+struct A : A<const T> {
+  A() { this->x; }
+};

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to