Skip to content

Conversation

@localspook
Copy link
Contributor

@localspook localspook commented Dec 7, 2025

Context: for every class, this check needs to compute whether that class is an interface (i.e. only has pure virtual methods). This is expensive, so the check caches the computation. But it caches by class name, which is problematic, because the same name can refer to different classes at different scopes. Here's for example a false negative it causes: https://godbolt.org/z/bMGc5sYqh. This PR changes it to cache by CXXRecordDecl * instead.

@llvmbot
Copy link
Member

llvmbot commented Dec 7, 2025

@llvm/pr-subscribers-clang-tidy

@llvm/pr-subscribers-clang-tools-extra

Author: Victor Chernyakin (localspook)

Changes

Context: for every class, this check needs to compute whether that class is an interface (i.e. only has pure virtual methods). This is expensive, so the check caches the computation. But it caches by class name, which is problematic, because the same name can refer to different classes at different scopes. Here's for example a false negative it causes: https://godbolt.org/z/bMGc5sYqh. This PR changes it to cache by CXXRecordDecl pointer.


Full diff: https://github.com/llvm/llvm-project/pull/171016.diff

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp (+2-9)
  • (modified) clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.h (+1-1)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/fuchsia/multiple-inheritance.cpp (+15)
diff --git a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
index 652dec9bcc2a9..029c482691c00 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
@@ -27,9 +27,7 @@ AST_MATCHER(CXXRecordDecl, hasBases) {
 // previously.
 void MultipleInheritanceCheck::addNodeToInterfaceMap(const CXXRecordDecl *Node,
                                                      bool IsInterface) {
-  assert(Node->getIdentifier());
-  const StringRef Name = Node->getIdentifier()->getName();
-  InterfaceMap.insert(std::make_pair(Name, IsInterface));
+  InterfaceMap.try_emplace(Node, IsInterface);
 }
 
 // Returns "true" if the boolean "isInterface" has been set to the
@@ -37,9 +35,7 @@ void MultipleInheritanceCheck::addNodeToInterfaceMap(const CXXRecordDecl *Node,
 // interface status for the current node is not yet known.
 bool MultipleInheritanceCheck::getInterfaceStatus(const CXXRecordDecl *Node,
                                                   bool &IsInterface) const {
-  assert(Node->getIdentifier());
-  const StringRef Name = Node->getIdentifier()->getName();
-  auto Pair = InterfaceMap.find(Name);
+  auto Pair = InterfaceMap.find(Node);
   if (Pair == InterfaceMap.end())
     return false;
   IsInterface = Pair->second;
@@ -59,9 +55,6 @@ bool MultipleInheritanceCheck::isCurrentClassInterface(
 }
 
 bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) {
-  if (!Node->getIdentifier())
-    return false;
-
   // Short circuit the lookup if we have analyzed this record before.
   bool PreviousIsInterfaceResult = false;
   if (getInterfaceStatus(Node, PreviousIsInterfaceResult))
diff --git a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.h b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.h
index 2e268432c17cf..b9055eb58a300 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.h
+++ b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.h
@@ -38,7 +38,7 @@ class MultipleInheritanceCheck : public ClangTidyCheck {
   // Contains the identity of each named CXXRecord as an interface.  This is
   // used to memoize lookup speeds and improve performance from O(N^2) to O(N),
   // where N is the number of classes.
-  llvm::StringMap<bool> InterfaceMap;
+  llvm::DenseMap<const CXXRecordDecl *, bool> InterfaceMap;
 };
 
 } // namespace clang::tidy::fuchsia
diff --git a/clang-tools-extra/test/clang-tidy/checkers/fuchsia/multiple-inheritance.cpp b/clang-tools-extra/test/clang-tidy/checkers/fuchsia/multiple-inheritance.cpp
index d53b3fde7736b..c60649f52cb94 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/fuchsia/multiple-inheritance.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/fuchsia/multiple-inheritance.cpp
@@ -148,3 +148,18 @@ void test_no_crash() {
   auto foo = []() {};
   WithTemplBase<decltype(foo)>();
 }
+
+struct S1 {};
+struct S2 {};
+
+struct S3 : S1, S2 {};
+
+namespace N {
+
+struct S1 { int i; };
+struct S2 { int i; };
+
+// CHECK-MESSAGES: [[@LINE+1]]:1: warning: inheriting multiple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+struct S3 : S1, S2 {};
+
+} // namespace N

Copy link
Contributor

@vbvictor vbvictor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add release notes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants