Skip to content

[libc] Update libc namespace clang-tidy checks #98424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 11, 2024
Merged

Conversation

ilovepi
Copy link
Contributor

@ilovepi ilovepi commented Jul 11, 2024

This patch updates the clang-tidy checks for llvm-libc to ensure that the namespace macro used to declare the libc namespace is updated from LIBC_NAMESPACE to LIBC_NAMESPACE_DECL which by default has hidden visibility.

Co-authored-by: Prabhu Rajesakeran [email protected]

Namespace macro that should be used to declare a new namespace is
updated from LIBC_NAMESPACE to LIBC_NAMESPACE_DECL which by default has
hidden visibility (llvm#97109). This commit updates the clang-tidy checks to
match the new policy.
@ilovepi ilovepi marked this pull request as ready for review July 11, 2024 02:52
@llvmbot
Copy link
Member

llvmbot commented Jul 11, 2024

@llvm/pr-subscribers-clang-tidy

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

Author: Paul Kirth (ilovepi)

Changes

This patch updates the clang-tidy checks for llvm-libc to ensure that the namespace macro used to declare the libc namespace is updated from LIBC_NAMESPACE to LIBC_NAMESPACE_DECL which by default has hidden visibility.

Co-authored-by: Prabhu Rajesakeran <[email protected]>


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

5 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp (+2-2)
  • (modified) clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp (+19-4)
  • (modified) clang-tools-extra/clang-tidy/llvmlibc/NamespaceConstants.h (+6-2)
  • (modified) clang-tools-extra/docs/clang-tidy/checks/llvmlibc/implementation-in-namespace.rst (+10-10)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/llvmlibc/implementation-in-namespace.cpp (+21-20)
diff --git a/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp
index af977bff70f7c..caa19c595823f 100644
--- a/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp
@@ -51,7 +51,7 @@ void CalleeNamespaceCheck::check(const MatchFinder::MatchResult &Result) {
   // __llvm_libc, we're good.
   const auto *NS = dyn_cast<NamespaceDecl>(getOutermostNamespace(FuncDecl));
   if (NS && Result.SourceManager->isMacroBodyExpansion(NS->getLocation()) &&
-      NS->getName().starts_with(RequiredNamespaceStart))
+      NS->getName().starts_with(RequiredNamespaceRefStart))
     return;
 
   const DeclarationName &Name = FuncDecl->getDeclName();
@@ -62,7 +62,7 @@ void CalleeNamespaceCheck::check(const MatchFinder::MatchResult &Result) {
   diag(UsageSiteExpr->getBeginLoc(),
        "%0 must resolve to a function declared "
        "within the namespace defined by the '%1' macro")
-      << FuncDecl << RequiredNamespaceMacroName;
+      << FuncDecl << RequiredNamespaceRefMacroName;
 
   diag(FuncDecl->getLocation(), "resolves to this declaration",
        clang::DiagnosticIDs::Note);
diff --git a/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp
index ae9819ed97502..bb436e4d12a30 100644
--- a/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvmlibc/ImplementationInNamespaceCheck.cpp
@@ -30,20 +30,35 @@ void ImplementationInNamespaceCheck::check(
   const auto *MatchedDecl =
       Result.Nodes.getNodeAs<Decl>("child_of_translation_unit");
   const auto *NS = dyn_cast<NamespaceDecl>(MatchedDecl);
+
+  // LLVM libc declarations should be inside of a non-anonymous namespace.
   if (NS == nullptr || NS->isAnonymousNamespace()) {
     diag(MatchedDecl->getLocation(),
          "declaration must be enclosed within the '%0' namespace")
-        << RequiredNamespaceMacroName;
+        << RequiredNamespaceDeclMacroName;
     return;
   }
+
+  // Enforce that the namespace is the result of macro expansion
   if (Result.SourceManager->isMacroBodyExpansion(NS->getLocation()) == false) {
     diag(NS->getLocation(), "the outermost namespace should be the '%0' macro")
-        << RequiredNamespaceMacroName;
+        << RequiredNamespaceDeclMacroName;
     return;
   }
-  if (NS->getName().starts_with(RequiredNamespaceStart) == false) {
+
+  // We want the macro to have [[gnu::visibility("hidden")]] as a prefix, but
+  // visibility is just an attribute in the AST construct, so we check that
+  // instead.
+  if (NS->getVisibility() != Visibility::HiddenVisibility) {
     diag(NS->getLocation(), "the '%0' macro should start with '%1'")
-        << RequiredNamespaceMacroName << RequiredNamespaceStart;
+        << RequiredNamespaceDeclMacroName << RequiredNamespaceDeclStart;
+    return;
+  }
+
+  // Lastly, make sure the namespace name actually has the __llvm_libc prefix
+  if (NS->getName().starts_with(RequiredNamespaceRefStart) == false) {
+    diag(NS->getLocation(), "the '%0' macro expansion should start with '%1'")
+        << RequiredNamespaceDeclMacroName << RequiredNamespaceRefStart;
     return;
   }
 }
diff --git a/clang-tools-extra/clang-tidy/llvmlibc/NamespaceConstants.h b/clang-tools-extra/clang-tidy/llvmlibc/NamespaceConstants.h
index 7d4120085b866..83908a7875d03 100644
--- a/clang-tools-extra/clang-tidy/llvmlibc/NamespaceConstants.h
+++ b/clang-tools-extra/clang-tidy/llvmlibc/NamespaceConstants.h
@@ -10,7 +10,11 @@
 
 namespace clang::tidy::llvm_libc {
 
-const static llvm::StringRef RequiredNamespaceStart = "__llvm_libc";
-const static llvm::StringRef RequiredNamespaceMacroName = "LIBC_NAMESPACE";
+const static llvm::StringRef RequiredNamespaceRefStart = "__llvm_libc";
+const static llvm::StringRef RequiredNamespaceRefMacroName = "LIBC_NAMESPACE";
+const static llvm::StringRef RequiredNamespaceDeclStart =
+    "[[gnu::visibility(\"hidden\")]] __llvm_libc";
+const static llvm::StringRef RequiredNamespaceDeclMacroName =
+    "LIBC_NAMESPACE_DECL";
 
 } // namespace clang::tidy::llvm_libc
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 47ea2b866a934..ec52b9f73a3f3 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,13 +8,13 @@ correct namespace.
 
 .. code-block:: c++
 
-    // Implementation inside the LIBC_NAMESPACE namespace.
+    // Implementation inside the LIBC_NAMESPACE_DECL namespace.
     // Correct if:
-    // - LIBC_NAMESPACE is a macro
-    // - LIBC_NAMESPACE expansion starts with `__llvm_libc`
-    namespace LIBC_NAMESPACE {
+    // - LIBC_NAMESPACE_DECL is a macro
+    // - LIBC_NAMESPACE_DECL expansion starts with `[[gnu::visibility("hidden")]] __llvm_libc`
+    namespace LIBC_NAMESPACE_DECL {
         void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
-        // Namespaces within LIBC_NAMESPACE namespace are allowed.
+        // Namespaces within LIBC_NAMESPACE_DECL namespace are allowed.
         namespace inner {
             int localVar = 0;
         }
@@ -22,16 +22,16 @@ correct namespace.
         extern "C" void str_fuzz() {}
     }
 
-    // Incorrect: implementation not in the LIBC_NAMESPACE namespace.
+    // Incorrect: implementation not in the LIBC_NAMESPACE_DECL namespace.
     void LLVM_LIBC_ENTRYPOINT(strcpy)(char *dest, const char *src) {}
 
-    // Incorrect: outer most namespace is not the LIBC_NAMESPACE macro.
+    // Incorrect: outer most namespace is not the LIBC_NAMESPACE_DECL 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 {
+    // Incorrect: outer most namespace expansion does not start with `[[gnu::visibility("hidden")]] __llvm_libc`.
+    #define LIBC_NAMESPACE_DECL custom_namespace
+    namespace LIBC_NAMESPACE_DECL {
         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 2246a430dd1f5..4a5576f2c5d62 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,60 +3,61 @@
 #define MACRO_A "defining macros outside namespace is valid"
 
 class ClassB;
-// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be enclosed within the 'LIBC_NAMESPACE_DECL' namespace
 struct StructC {};
-// 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 enclosed within the 'LIBC_NAMESPACE' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration must be enclosed within the 'LIBC_NAMESPACE_DECL' namespace
+const char *VarD = MACRO_A;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration must be enclosed within the 'LIBC_NAMESPACE_DECL' namespace
 typedef int typeE;
-// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: declaration must be enclosed within the 'LIBC_NAMESPACE_DECL' namespace
 void funcF() {}
-// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: declaration must be enclosed within the 'LIBC_NAMESPACE_DECL' namespace
 
 namespace outer_most {
-// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the outermost namespace should be the 'LIBC_NAMESPACE' macro
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the outermost namespace should be the 'LIBC_NAMESPACE_DECL' macro
  class A {};
 }
 
 // Wrapped in anonymous namespace.
 namespace {
-// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: declaration must be enclosed within the 'LIBC_NAMESPACE_DECL' namespace
  class A {};
 }
 
 namespace namespaceG {
-// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the outermost namespace should be the 'LIBC_NAMESPACE' macro
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the outermost namespace should be the 'LIBC_NAMESPACE_DECL' macro
 namespace __llvm_libc {
 namespace namespaceH {
 class ClassB;
 } // namespace namespaceH
 struct StructC {};
 } // namespace __llvm_libc
-char *VarD = MACRO_A;
+const char *VarD = MACRO_A;
 typedef int typeE;
 void funcF() {}
 } // namespace namespaceG
 
 // 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'
+#define LIBC_NAMESPACE_DECL [[gnu::visibility("hidden")]] custom_namespace
+namespace LIBC_NAMESPACE_DECL {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the 'LIBC_NAMESPACE_DECL' macro expansion should start with '__llvm_libc'
+
 namespace namespaceH {
 class ClassB;
 } // namespace namespaceH
-} // namespace LIBC_NAMESPACE
+} // namespace LIBC_NAMESPACE_DECL
 
 
-// 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 {
+// Wrapped in macro namespace with a valid name, LIBC_NAMESPACE_DECL starts with '__llvm_libc'
+#undef LIBC_NAMESPACE_DECL
+#define LIBC_NAMESPACE_DECL [[gnu::visibility("hidden")]] __llvm_libc_xyz
+namespace LIBC_NAMESPACE_DECL {
 namespace namespaceI {
 class ClassB;
 } // namespace namespaceI
 struct StructC {};
-char *VarD = MACRO_A;
+const char *VarD = MACRO_A;
 typedef int typeE;
 void funcF() {}
 extern "C" void extern_funcJ() {}
-} // namespace LIBC_NAMESPACE
+} // namespace LIBC_NAMESPACE_DECL

char *VarD = MACRO_A;
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration must be enclosed within the 'LIBC_NAMESPACE' namespace
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: declaration must be enclosed within the 'LIBC_NAMESPACE_DECL' namespace
const char *VarD = MACRO_A;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I know this is a bit unrelated, but the tidy output was pretty polluted with warnings due to the lack of const here. When I manually ran the tidy command + Filecheck, it seemed to fail due to those warnings, so I just fixed those since I was changing these checks anyway.

@ilovepi
Copy link
Contributor Author

ilovepi commented Jul 11, 2024

Also, as an FYI to reviewers, I'm working on the FixIts for these as a separate patch.

Copy link
Member

@PiotrZSL PiotrZSL left a comment

Choose a reason for hiding this comment

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

LGTM

@ilovepi ilovepi merged commit a074f88 into llvm:main Jul 11, 2024
13 checks passed
@ilovepi ilovepi deleted the libc_tidy branch July 11, 2024 20:36
aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
This patch updates the clang-tidy checks for llvm-libc to ensure that
the namespace macro used to declare the libc namespace is updated from
LIBC_NAMESPACE to LIBC_NAMESPACE_DECL which by default has hidden
visibility.

Co-authored-by: Prabhu Rajesakeran <[email protected]>
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.

4 participants