[clang-tools-extra] 3887ae1 - [clang-tidy] Guard `readability-identifier-naming` recursion in dependent base lookup (#204913)

via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 25 00:31:42 PDT 2026


Author: Zihan Qin
Date: 2026-06-25T15:31:37+08:00
New Revision: 3887ae1aacf6799e83684ab2bd0d02fd6b169ccd

URL: https://github.com/llvm/llvm-project/commit/3887ae1aacf6799e83684ab2bd0d02fd6b169ccd
DIFF: https://github.com/llvm/llvm-project/commit/3887ae1aacf6799e83684ab2bd0d02fd6b169ccd.diff

LOG: [clang-tidy] Guard `readability-identifier-naming` recursion in dependent base lookup (#204913)

Prevent `readability-identifier-naming` from recursing indefinitely in
dependent base lookup when AggressiveDependentMemberLookup` is enabled.

In #204790, `findDeclInBases()` maps a dependent template base back to
the primary template, creating a recursive cycle that crashes
clang-tidy. Add a recursion guard to stop the crash. A more complete fix
could be explored separately.

Add a regression test covering the dependent base cycle reproducer.

Closes https://github.com/llvm/llvm-project/issues/204790.

---------

Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-member-decl-usage.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
index cb7ef19827675..bfdcd381b4122 100644
--- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
@@ -17,6 +17,7 @@
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/ScopeExit.h"
 #include <optional>
 
 #define DEBUG_TYPE "clang-tidy"
@@ -118,6 +119,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 +128,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 +155,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 +312,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/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 4a5863be59fe3..81e5de4e0a868 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -801,6 +801,9 @@ Changes in existing checks
   - Fixed a false positive where function templates could be diagnosed as generic
     identifiers when `DefaultCase` was enabled.
 
+  - Fixed a crash in dependent base lookup when
+    `AggressiveDependentMemberLookup` option is enabled.
+
 - Improved :doc:`readability-implicit-bool-conversion
   <clang-tidy/checks/readability/implicit-bool-conversion>` check:
 

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-member-decl-usage.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-member-decl-usage.cpp
index 61c3aeb043934..ce7065dc0643e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-member-decl-usage.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-member-decl-usage.cpp
@@ -216,3 +216,18 @@ struct Derived : DependentBase<T> {
 };
 
 } // namespace unresolved_dependance
+
+namespace dependent_base_cycle {
+template <typename T>
+struct CycleBase;
+
+template <typename T>
+struct CycleBase<const T> {
+  int Value;
+};
+
+template <typename T>
+struct CycleBase : CycleBase<const T> {
+  CycleBase() { this->Value; }
+};
+} // namespace dependent_base_cycle


        


More information about the cfe-commits mailing list