Author: Baranov Victor
Date: 2025-07-12T20:05:05+03:00
New Revision: 45f7285d0ef35615cc9ba665ed54fdb4c6d1c711

URL: 
https://github.com/llvm/llvm-project/commit/45f7285d0ef35615cc9ba665ed54fdb4c6d1c711
DIFF: 
https://github.com/llvm/llvm-project/commit/45f7285d0ef35615cc9ba665ed54fdb4c6d1c711.diff

LOG: [clang-tidy] Use lexical anon-ns matcher in 
llvm-prefer-static-over-anonymous-namespace (#148357)

When having this code:
```cpp
namespace {
class MyClassOutOfAnon {
public:
  MyClassOutOfAnon();
} // namespace

MyClassOutOfAnon::MyClassOutOfAnon() {}
```
`MyClassOutOfAnon::MyClassOutOfAnon` is located in anonymous namespace
in `DeclContext` but outside anonymous namespace in
`LexicalDeclContext`.

For this check to work correctly, we need to check if definition is
located inside `LexicalDeclContext`.

Added: 
    

Modified: 
    
clang-tools-extra/clang-tidy/llvm/PreferStaticOverAnonymousNamespaceCheck.cpp
    
clang-tools-extra/test/clang-tidy/checkers/llvm/prefer-static-over-anonymous-namespace.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang-tools-extra/clang-tidy/llvm/PreferStaticOverAnonymousNamespaceCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/PreferStaticOverAnonymousNamespaceCheck.cpp
index 592f0986292f2..ea79bfaef8876 100644
--- 
a/clang-tools-extra/clang-tidy/llvm/PreferStaticOverAnonymousNamespaceCheck.cpp
+++ 
b/clang-tools-extra/clang-tidy/llvm/PreferStaticOverAnonymousNamespaceCheck.cpp
@@ -21,6 +21,17 @@ AST_MATCHER(NamedDecl, isInMacro) {
 
 AST_MATCHER(VarDecl, isLocalVariable) { return Node.isLocalVarDecl(); }
 
+AST_MATCHER(Decl, isLexicallyInAnonymousNamespace) {
+  for (const DeclContext *DC = Node.getLexicalDeclContext(); DC != nullptr;
+       DC = DC->getLexicalParent()) {
+    if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
+      if (ND->isAnonymousNamespace())
+        return true;
+  }
+
+  return false;
+}
+
 } // namespace
 
 PreferStaticOverAnonymousNamespaceCheck::
@@ -40,9 +51,9 @@ void PreferStaticOverAnonymousNamespaceCheck::storeOptions(
 
 void PreferStaticOverAnonymousNamespaceCheck::registerMatchers(
     MatchFinder *Finder) {
-  const auto IsDefinitionInAnonymousNamespace =
-      allOf(unless(isExpansionInSystemHeader()), isInAnonymousNamespace(),
-            unless(isInMacro()), isDefinition());
+  const auto IsDefinitionInAnonymousNamespace = allOf(
+      unless(isExpansionInSystemHeader()), isLexicallyInAnonymousNamespace(),
+      unless(isInMacro()), isDefinition());
 
   if (AllowMemberFunctionsInClass) {
     Finder->addMatcher(

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/prefer-static-over-anonymous-namespace.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/prefer-static-over-anonymous-namespace.cpp
index f0ffafcf18e67..71dce6ea4f01c 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/prefer-static-over-anonymous-namespace.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/prefer-static-over-anonymous-namespace.cpp
@@ -178,6 +178,95 @@ void OuterClass::NestedClass::nestedMemberFunc() {}
 
 } // namespace
 
+namespace {
+
+class MyClassOutOfAnon {
+public:
+  MyClassOutOfAnon();
+  MyClassOutOfAnon(const MyClassOutOfAnon&) {}
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:3: warning: place definition of method 
'MyClassOutOfAnon' outside of an anonymous namespace
+  MyClassOutOfAnon(MyClassOutOfAnon&&) = default;
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:3: warning: place definition of method 
'MyClassOutOfAnon' outside of an anonymous namespace
+  MyClassOutOfAnon& operator=(const MyClassOutOfAnon&);
+  MyClassOutOfAnon& operator=(MyClassOutOfAnon&&);
+  bool operator<(const MyClassOutOfAnon&) const;
+  void memberFunction();
+  static void staticMemberFunction();
+  void memberDefinedInClass() {}
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:8: warning: place definition of method 
'memberDefinedInClass' outside of an anonymous namespace
+  static void staticMemberDefinedInClass() {}
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:15: warning: place definition of method 
'staticMemberDefinedInClass' outside of an anonymous namespace
+  template <typename T>
+  void templateFunction();
+  template <typename T>
+  void templateFunctionInClass() {}
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:8: warning: place definition of method 
'templateFunctionInClass' outside of an anonymous namespace
+};
+
+} // namespace
+
+MyClassOutOfAnon::MyClassOutOfAnon() {}
+
+MyClassOutOfAnon& MyClassOutOfAnon::operator=(const MyClassOutOfAnon&) { 
return *this; }
+
+MyClassOutOfAnon& MyClassOutOfAnon::operator=(MyClassOutOfAnon&&) = default;
+
+bool MyClassOutOfAnon::operator<(const MyClassOutOfAnon&) const { return true; 
}
+
+void MyClassOutOfAnon::memberFunction() {}
+
+void MyClassOutOfAnon::staticMemberFunction() {}
+
+template <typename T>
+void MyClassOutOfAnon::templateFunction() {}
+
+namespace {
+
+template<typename T>
+class TemplateClassOutOfAnon {
+  public:
+  TemplateClassOutOfAnon();
+  TemplateClassOutOfAnon(const TemplateClassOutOfAnon&) {}
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:3: warning: place definition of method 
'TemplateClassOutOfAnon<T>' outside of an anonymous namespace
+  TemplateClassOutOfAnon(TemplateClassOutOfAnon&&) = default;
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:3: warning: place definition of method 
'TemplateClassOutOfAnon<T>' outside of an anonymous namespace
+  TemplateClassOutOfAnon& operator=(const TemplateClassOutOfAnon&);
+  TemplateClassOutOfAnon& operator=(TemplateClassOutOfAnon&&);
+  bool operator<(const TemplateClassOutOfAnon&) const;
+  void memberFunc();
+  T getValue() const;
+  void memberDefinedInClass() {}
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:8: warning: place definition of method 
'memberDefinedInClass' outside of an anonymous namespace
+  static void staticMemberDefinedInClass() {}
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:15: warning: place definition of method 
'staticMemberDefinedInClass' outside of an anonymous namespace
+  template <typename U>
+  void templateMethodInTemplateClass() {}
+  // CHECK-MESSAGES-MEM: :[[@LINE-1]]:8: warning: place definition of method 
'templateMethodInTemplateClass' outside of an anonymous namespace
+  private:
+  T Value;
+};
+
+} // namespace
+
+template<typename T>
+TemplateClassOutOfAnon<T>::TemplateClassOutOfAnon() {}
+
+template<typename T>
+TemplateClassOutOfAnon<T>& TemplateClassOutOfAnon<T>::operator=(const 
TemplateClassOutOfAnon&) { return *this; }
+
+template<typename T>
+TemplateClassOutOfAnon<T>& 
TemplateClassOutOfAnon<T>::operator=(TemplateClassOutOfAnon&&) = default;
+
+template<typename T>
+bool TemplateClassOutOfAnon<T>::operator<(const TemplateClassOutOfAnon&) const 
{ return true; }
+
+template<typename T>
+void TemplateClassOutOfAnon<T>::memberFunc() {}
+
+template<typename T>
+T TemplateClassOutOfAnon<T>::getValue() const { return Value; }
+
+
 #define DEFINE_FUNCTION(name) \
   namespace { \
     void name() {} \


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to