[clang-tools-extra] 774116b - [clang-tidy] Update llvmlibc-implementation-in-namespace to new rules (#66504)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 21 08:05:51 PDT 2023


Author: Guillaume Chatelet
Date: 2023-09-21T17:05:47+02:00
New Revision: 774116b8f669a5a1fc12aaef6ebb408a5f064172

URL: https://github.com/llvm/llvm-project/commit/774116b8f669a5a1fc12aaef6ebb408a5f064172
DIFF: https://github.com/llvm/llvm-project/commit/774116b8f669a5a1fc12aaef6ebb408a5f064172.diff

LOG: [clang-tidy] Update llvmlibc-implementation-in-namespace to new rules (#66504)

This is the implementation of step 3 of

https://discourse.llvm.org/t/rfc-customizable-namespace-to-allow-testing-the-libc-when-the-system-libc-is-also-llvms-libc/73079.

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/llvmlibc/implementation-in-namespace.rst
    clang-tools-extra/test/clang-tidy/checkers/llvmlibc/implementation-in-namespace.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp
index d05310f09ef773a..4489179c4423419 100644
--- a/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp
@@ -14,11 +14,16 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::llvm_libc {
 
-const static StringRef RequiredNamespace = "__llvm_libc";
+const static StringRef RequiredNamespaceStart = "__llvm_libc";
+const static StringRef RequiredNamespaceMacroName = "LIBC_NAMESPACE";
+
 void ImplementationInNamespaceCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      decl(hasParent(translationUnitDecl()), unless(linkageSpecDecl()))
-          .bind("child_of_translation_unit"),
+      translationUnitDecl(
+          forEach(decl(isExpansionInMainFile(), unless(linkageSpecDecl()),
+                       // anonymous namespaces generate usingDirective
+                       unless(usingDirectiveDecl(isImplicit())))
+                      .bind("child_of_translation_unit"))),
       this);
 }
 
@@ -26,19 +31,24 @@ void ImplementationInNamespaceCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *MatchedDecl =
       Result.Nodes.getNodeAs<Decl>("child_of_translation_unit");
-  if (!Result.SourceManager->isInMainFile(MatchedDecl->getLocation()))
+  MatchedDecl->dump();
+  const auto *NS = dyn_cast<NamespaceDecl>(MatchedDecl);
+  if (NS == nullptr || NS->isAnonymousNamespace()) {
+    diag(MatchedDecl->getLocation(),
+         "declaration must be enclosed within the '%0' namespace")
+        << RequiredNamespaceMacroName;
     return;
-
-  if (const auto *NS = dyn_cast<NamespaceDecl>(MatchedDecl)) {
-    if (NS->getName() != RequiredNamespace) {
-      diag(NS->getLocation(), "'%0' needs to be the outermost namespace")
-          << RequiredNamespace;
-    }
+  }
+  if (Result.SourceManager->isMacroBodyExpansion(NS->getLocation()) == false) {
+    diag(NS->getLocation(), "the outermost namespace should be the '%0' macro")
+        << RequiredNamespaceMacroName;
+    return;
+  }
+  if (NS->getName().starts_with(RequiredNamespaceStart) == false) {
+    diag(NS->getLocation(), "the '%0' macro should start with '%1'")
+        << RequiredNamespaceMacroName << RequiredNamespaceStart;
     return;
   }
-  diag(MatchedDecl->getLocation(),
-       "declaration must be declared within the '%0' namespace")
-      << RequiredNamespace;
 }
 
 } // namespace clang::tidy::llvm_libc

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index b4660db333f3c14..466c9b08c578890 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -241,6 +241,11 @@ Changes in existing checks
   <clang-tidy/checks/llvm/namespace-comment>` check to provide fixes for
   ``inline`` namespaces in the same format as :program:`clang-format`.
 
+- Improved :doc:`llvmlibc-implementation-in-namespace
+  <clang-tidy/checks/llvmlibc/implementation-in-namespace>` to support
+  customizable namespace. This further allows for testing the libc when the
+  system-libc is also LLVM's libc.
+
 - Improved :doc:`misc-include-cleaner
   <clang-tidy/checks/misc/include-cleaner>` check by adding option
   `DeduplicateFindings` to output one finding per symbol occurrence.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/implementation-in-namespace.rst b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/implementation-in-namespace.rst
index 33d6dc8ff125c84..47ea2b866a93404 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/implementation-in-namespace.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/implementation-in-namespace.rst
@@ -8,21 +8,30 @@ correct namespace.
 
 .. code-block:: c++
 
-    // Correct: implementation inside the correct namespace.
-    namespace __llvm_libc {
+    // Implementation inside the LIBC_NAMESPACE namespace.
+    // Correct if:
+    // - LIBC_NAMESPACE is a macro
+    // - LIBC_NAMESPACE expansion starts with `__llvm_libc`
+    namespace LIBC_NAMESPACE {
         void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
-        // Namespaces within __llvm_libc namespace are allowed.
-        namespace inner{
+        // Namespaces within LIBC_NAMESPACE namespace are allowed.
+        namespace inner {
             int localVar = 0;
         }
         // Functions with C linkage are allowed.
-        extern "C" void str_fuzz(){}
+        extern "C" void str_fuzz() {}
     }
 
-    // Incorrect: implementation not in a namespace.
+    // Incorrect: implementation not in the LIBC_NAMESPACE namespace.
     void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
 
-    // Incorrect: outer most namespace is not correct.
+    // Incorrect: outer most namespace is not the LIBC_NAMESPACE macro.
     namespace something_else {
         void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
     }
+
+    // Incorrect: outer most namespace expansion does not start with `__llvm_libc`.
+    #define LIBC_NAMESPACE custom_namespace
+    namespace LIBC_NAMESPACE {
+        void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
+    }

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/implementation-in-namespace.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/implementation-in-namespace.cpp
index e75556a623b655c..2246a430dd1f573 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/implementation-in-namespace.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/implementation-in-namespace.cpp
@@ -3,19 +3,30 @@
 #define MACRO_A "defining macros outside namespace is valid"
 
 class ClassB;
-// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be declared within the '__llvm_libc' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
 struct StructC {};
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration must be declared within the '__llvm_libc' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
 char *VarD = MACRO_A;
-// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be declared within the '__llvm_libc' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
 typedef int typeE;
-// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration must be declared within the '__llvm_libc' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
 void funcF() {}
-// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration must be declared within the '__llvm_libc' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
+
+namespace outer_most {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the outermost namespace should be the 'LIBC_NAMESPACE' macro
+ class A {};
+}
+
+// Wrapped in anonymous namespace.
+namespace {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
+ class A {};
+}
 
 namespace namespaceG {
-// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: '__llvm_libc' needs to be the outermost namespace
-namespace __llvm_libc{
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the outermost namespace should be the 'LIBC_NAMESPACE' macro
+namespace __llvm_libc {
 namespace namespaceH {
 class ClassB;
 } // namespace namespaceH
@@ -26,9 +37,20 @@ typedef int typeE;
 void funcF() {}
 } // namespace namespaceG
 
-// Wrapped in correct namespace.
-namespace __llvm_libc {
-// Namespaces within __llvim_libc namespace allowed.
+// Wrapped in macro namespace but with an incorrect name
+#define LIBC_NAMESPACE custom_namespace
+namespace LIBC_NAMESPACE {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the 'LIBC_NAMESPACE' macro should start with '__llvm_libc'
+namespace namespaceH {
+class ClassB;
+} // namespace namespaceH
+} // namespace LIBC_NAMESPACE
+
+
+// Wrapped in macro namespace with a valid name, LIBC_NAMESPACE starts with '__llvm_libc'
+#undef LIBC_NAMESPACE
+#define LIBC_NAMESPACE __llvm_libc_xyz
+namespace LIBC_NAMESPACE {
 namespace namespaceI {
 class ClassB;
 } // namespace namespaceI
@@ -37,4 +59,4 @@ char *VarD = MACRO_A;
 typedef int typeE;
 void funcF() {}
 extern "C" void extern_funcJ() {}
-} // namespace __llvm_libc
+} // namespace LIBC_NAMESPACE


        


More information about the cfe-commits mailing list