[clang] [clang] Ignore inline namespace for `hasName` (PR #109147)

via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 18 07:00:29 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Alejandro Álvarez Ayllón (alejandro-alvarez-sonarsource)

<details>
<summary>Changes</summary>

Add a new flag `AlwaysSuppressInlineNamespace` to `PrintingPolicy` that is explicit
about *always* removing inline namespaces regardless of ambiguity.

Specializing a template from an inline namespace should be transparent. For instance

```
namespace foo {
    inline namespace v1 {
        template<typename A>
        void function(A&);
    }
}

namespace foo {
    template<>
    void function<int>(int&);
}
```

`hasName` should match both declarations of `foo::function`.

Makes the behavior of `matchesNodeFullSlow` and `matchesNodeFullFast` consistent, fixing
an assert inside `HasNameMatcher::matchesNode`.

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


4 Files Affected:

- (modified) clang/include/clang/AST/PrettyPrinter.h (+8-3) 
- (modified) clang/lib/AST/Decl.cpp (+5-2) 
- (modified) clang/lib/ASTMatchers/ASTMatchersInternal.cpp (+1) 
- (modified) clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (+29) 


``````````diff
diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index 332ac3c6a004a9..a671211bf3ef93 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -61,9 +61,9 @@ struct PrintingPolicy {
         SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
         SuppressScope(false), SuppressUnwrittenScope(false),
         SuppressInlineNamespace(true), SuppressElaboration(false),
-        SuppressInitializers(false), ConstantArraySizeAsWritten(false),
-        AnonymousTagLocations(true), SuppressStrongLifetime(false),
-        SuppressLifetimeQualifiers(false),
+        AlwaysSuppressInlineNamespace(false), SuppressInitializers(false),
+        ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
+        SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
         SuppressTemplateArgsInCXXConstructors(false),
         SuppressDefaultTemplateArgs(true), Bool(LO.Bool),
         Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus),
@@ -151,6 +151,11 @@ struct PrintingPolicy {
   LLVM_PREFERRED_TYPE(bool)
   unsigned SuppressElaboration : 1;
 
+  /// Suppress printing parts of scope specifiers that correspond
+  /// to inline namespaces, even if the name is ambiguous with the specifier
+  /// removed.
+  unsigned AlwaysSuppressInlineNamespace : 1;
+
   /// Suppress printing of variable initializers.
   ///
   /// This flag is used when printing the loop variable in a for-range
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index a14b1b33d35efc..a3ac12d58ed044 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1737,8 +1737,11 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
       continue;
 
     // Suppress inline namespace if it doesn't make the result ambiguous.
-    if (P.SuppressInlineNamespace && Ctx->isInlineNamespace() && NameInScope &&
-        cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor(NameInScope))
+    if (Ctx->isInlineNamespace() && NameInScope &&
+        (P.AlwaysSuppressInlineNamespace ||
+         (P.SuppressInlineNamespace &&
+          cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor(
+              NameInScope))))
       continue;
 
     // Skip non-named contexts such as linkage specifications and ExportDecls.
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 06309d327896b3..731fc97707eee7 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -656,6 +656,7 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const {
     PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
     Policy.SuppressUnwrittenScope = SkipUnwritten;
     Policy.SuppressInlineNamespace = SkipUnwritten;
+    Policy.AlwaysSuppressInlineNamespace = SkipUnwritten;
     Node.printQualifiedName(OS, Policy);
 
     const StringRef FullName = OS.str();
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 611e1f9ba5327c..d696375547acce 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2599,6 +2599,35 @@ TEST_P(ASTMatchersTest, HasName_MatchesInlinedNamespaces) {
   EXPECT_TRUE(matches(code, recordDecl(hasName("::a::C"))));
 }
 
+TEST_P(ASTMatchersTest, HasName_MatchesSpecializedInlinedNamespace) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+
+  StringRef code = R"(
+namespace a {
+    inline namespace v1 {
+        template<typename T> T foo(T);
+    }
+}
+
+namespace a {
+    enum Tag{T1, T2};
+
+    template <Tag, typename T> T foo(T);
+}
+
+auto v1 = a::foo(1);
+auto v2 = a::foo<a::T1>(1);
+)";
+  EXPECT_TRUE(matches(
+      code, varDecl(hasName("v1"), hasDescendant(callExpr(callee(
+                                       functionDecl(hasName("::a::foo"))))))));
+  EXPECT_TRUE(matches(
+      code, varDecl(hasName("v2"), hasDescendant(callExpr(callee(
+                                       functionDecl(hasName("::a::foo"))))))));
+}
+
 TEST_P(ASTMatchersTest, HasName_MatchesAnonymousNamespaces) {
   if (!GetParam().isCXX()) {
     return;

``````````

</details>


https://github.com/llvm/llvm-project/pull/109147


More information about the cfe-commits mailing list