junaire updated this revision to Diff 397842.
junaire added a comment.

After Aarron's comments, I realize what I really want to do is add a new
ASTMatcher that matches declarations what in the top level namespace like std.

This update fixed previous broken one, added some comments and unit tests.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115936/new/

https://reviews.llvm.org/D115936

Files:
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/AST/DeclBase.cpp
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -3478,6 +3478,33 @@
   EXPECT_TRUE(matches("namespace {}", namespaceDecl(isAnonymous())));
 }
 
+TEST_P(ASTMatchersTest, InTopNamespace) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(notMatches(
+      "namespace boost {"
+      "  namespace detail {"
+      "    class shared_ptr {};"
+      "  }"
+      "}",
+      cxxRecordDecl(hasName("shared_ptr"), isInTopNamespace("boost"))));
+
+  EXPECT_TRUE(
+      matches("namespace boost {"
+              "  class shared_ptr {};"
+              "}",
+              cxxRecordDecl(hasName("shared_ptr"), isInTopNamespace("boost"))));
+
+  EXPECT_TRUE(
+      matches("namespace boost {"
+              "  inline namespace __1 {"
+              "    class shared_ptr {};"
+              "  }"
+              "}",
+              cxxRecordDecl(hasName("shared_ptr"), isInTopNamespace("boost"))));
+}
+
 TEST_P(ASTMatchersTest, InStdNamespace) {
   if (!GetParam().isCXX()) {
     return;
Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -391,9 +391,11 @@
   return false;
 }
 
-bool Decl::isInStdNamespace() const {
+bool Decl::isInStdNamespace() const { return isInTopNamespace("std"); }
+
+bool Decl::isInTopNamespace(llvm::StringRef Namespace) const {
   const DeclContext *DC = getDeclContext();
-  return DC && DC->isStdNamespace();
+  return DC && DC->isTopNamespace(Namespace);
 }
 
 TranslationUnitDecl *Decl::getTranslationUnitDecl() {
@@ -1123,20 +1125,21 @@
          cast<NamespaceDecl>(this)->isInline();
 }
 
-bool DeclContext::isStdNamespace() const {
+bool DeclContext::isStdNamespace() const { return isTopNamespace("std"); }
+bool DeclContext::isTopNamespace(llvm::StringRef Namespace) const {
   if (!isNamespace())
     return false;
 
   const auto *ND = cast<NamespaceDecl>(this);
   if (ND->isInline()) {
-    return ND->getParent()->isStdNamespace();
+    return ND->getParent()->isTopNamespace(Namespace);
   }
 
   if (!getParent()->getRedeclContext()->isTranslationUnit())
     return false;
 
   const IdentifierInfo *II = ND->getIdentifier();
-  return II && II->isStr("std");
+  return II && II->isStr(Namespace);
 }
 
 bool DeclContext::isDependentContext() const {
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7675,6 +7675,29 @@
   return Node.isAnonymousNamespace();
 }
 
+/// Matches declarations in the top level namespace, but not in nested
+/// namespaces. This is because nested namespaces are designed for
+/// implementation details, we don't need to match them.
+///
+/// Given
+/// \code
+///   class shared_ptr {};
+///   namespace boost {
+///     class shared_ptr {}; #1
+///     namespace detail {
+///       class shared_ptr {};
+///     }
+///     inline namespace __1 {
+///       class shared_ptr {}; #2
+///     }
+///   }
+/// \endcode
+/// cxxRecordDecl(hasName("shared_ptr"), isInTopNamespace("boost")) will match
+/// #1 and #2.
+AST_MATCHER_P(Decl, isInTopNamespace, llvm::StringRef, Namespace) {
+  return Node.isInTopNamespace(Namespace);
+}
+
 /// Matches declarations in the namespace `std`, but not in nested namespaces.
 ///
 /// Given
Index: clang/include/clang/AST/DeclBase.h
===================================================================
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -462,6 +462,10 @@
 
   bool isInAnonymousNamespace() const;
 
+  /// Helper to check if a Decl in a specific top level namespace, while inline
+  /// namespaces will be skipped.
+  bool isInTopNamespace(llvm::StringRef) const;
+
   bool isInStdNamespace() const;
 
   ASTContext &getASTContext() const LLVM_READONLY;
@@ -1943,6 +1947,8 @@
 
   bool isNamespace() const { return getDeclKind() == Decl::Namespace; }
 
+  bool isTopNamespace(llvm::StringRef Namespace) const;
+
   bool isStdNamespace() const;
 
   bool isInlineNamespace() const;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to