Skip to content

Fix hasName matcher assertion with inline namespaces #100975

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 29, 2024

Conversation

njames93
Copy link
Member

Fix handling of nodes which can be skipped in the fast path for the hasName matcher

#100973

@llvmbot llvmbot added the clang Clang issues not falling into any other category label Jul 29, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 29, 2024

@llvm/pr-subscribers-clang

Author: Nathan James (njames93)

Changes

Fix handling of nodes which can be skipped in the fast path for the hasName matcher

#100973


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

2 Files Affected:

  • (modified) clang/lib/ASTMatchers/ASTMatchersInternal.cpp (+14-7)
  • (modified) clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (+4)
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index bf87b1aa0992a..0556ae7ffae2f 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -537,14 +537,21 @@ class PatternSet {
   /// that didn't match.
   /// Return true if there are still any patterns left.
   bool consumeNameSuffix(StringRef NodeName, bool CanSkip) {
-    for (size_t I = 0; I < Patterns.size();) {
-      if (::clang::ast_matchers::internal::consumeNameSuffix(Patterns[I].P,
-                                                             NodeName) ||
-          CanSkip) {
-        ++I;
-      } else {
-        Patterns.erase(Patterns.begin() + I);
+    if (CanSkip) {
+      // If we can skip the node, then we need to handle the case where a
+      // skipped node has the same name as its parent.
+      // namespace a { inline namespace a { class A; } }
+      // cxxRecordDecl(hasName("::a::A")) 
+      // To do this, any patterns that match should be duplicated in our set, one of them with the tail removed.
+      for (size_t I = 0, E = Patterns.size(); I != E; ++I) {
+        StringRef Pattern = Patterns[I].P;
+        if (ast_matchers::internal::consumeNameSuffix(Patterns[I].P, NodeName))
+          Patterns.push_back({Pattern, Patterns[I].IsFullyQualified});
       }
+    } else {
+      llvm::erase_if(Patterns, [&NodeName](auto &Pattern) {
+        return !::clang::ast_matchers::internal::consumeNameSuffix(Pattern.P, NodeName);
+      });
     }
     return !Patterns.empty();
   }
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index f26140675fd46..611e1f9ba5327 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2552,6 +2552,10 @@ TEST_P(ASTMatchersTest, HasName_MatchesNamespaces) {
                          recordDecl(hasName("a+b::C"))));
   EXPECT_TRUE(notMatches("namespace a { namespace b { class AC; } }",
                          recordDecl(hasName("C"))));
+  EXPECT_TRUE(matches("namespace a { inline namespace a { class C; } }",
+                      recordDecl(hasName("::a::C"))));
+  EXPECT_TRUE(matches("namespace a { inline namespace a { class C; } }",
+                      recordDecl(hasName("::a::a::C"))));
 }
 
 TEST_P(ASTMatchersTest, HasName_MatchesOuterClasses) {

@njames93 njames93 force-pushed the hasName-matcher-inline-fix branch from 8d1aeca to 9e3f5ae Compare July 29, 2024 06:23
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

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

I can't get the assertion to reproduce, but I can see the behavioral change with the first matcher: https://godbolt.org/z/TcsYPoGEh

So this should probably come with a release note for the fix?

@njames93
Copy link
Member Author

I can't get the assertion to reproduce, but I can see the behavioral change with the first matcher: https://godbolt.org/z/TcsYPoGEh

So this should probably come with a release note for the fix?

The assertions are only shown on debug build, but it comes from here

Which section in the release notes do changes to AST matchers belong in

@AaronBallman
Copy link
Collaborator

I can't get the assertion to reproduce, but I can see the behavioral change with the first matcher: https://godbolt.org/z/TcsYPoGEh
So this should probably come with a release note for the fix?

The assertions are only shown on debug build, but it comes from here

That should still trigger with an assertions build though, right?

Which section in the release notes do changes to AST matchers belong in

Somewhere around here:

Fix handling of nodes which can be skipped in the fast path for the
hasName matcher
@njames93 njames93 force-pushed the hasName-matcher-inline-fix branch from 9e3f5ae to b208791 Compare July 29, 2024 15:22
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

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

LGTM!

@njames93 njames93 merged commit f9e7cba into llvm:main Jul 29, 2024
8 checks passed
@njames93 njames93 deleted the hasName-matcher-inline-fix branch July 29, 2024 18:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants