[clang] [clang][ASTMatcher] Add `matchesString` for `StringLiteral` which matches literals on given `RegExp` (PR #102152)

via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 8 22:43:21 PDT 2024


https://github.com/Gitspike updated https://github.com/llvm/llvm-project/pull/102152

>From 0d8191b5d205c811364cf1f1b184bcbc9bbeda7f Mon Sep 17 00:00:00 2001
From: hehouhua <hehouhua at feysh.com>
Date: Wed, 7 Aug 2024 11:55:30 +0800
Subject: [PATCH 1/4] [clang][ASTMatcher] Add matches for StringLiteral which
 matches literals on given RegExp

Add Matcher matchesString.
---
 clang/docs/LibASTMatchersReference.html       | 14 +++++++++++
 clang/docs/ReleaseNotes.rst                   |  2 ++
 clang/include/clang/ASTMatchers/ASTMatchers.h | 24 +++++++++++++++++++
 clang/lib/ASTMatchers/Dynamic/Registry.cpp    |  1 +
 .../ASTMatchers/ASTMatchersNarrowingTest.cpp  | 19 +++++++++++++++
 5 files changed, 60 insertions(+)

diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index a16b9c44ef0eab..77b789b1ec4b94 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -5582,6 +5582,20 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
 </pre></td></tr>
 
 
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1StringLiteral.html">StringLiteral</a>></td><td class="name" onclick="toggle('matchesString0')"><a name="matchesString0A">matchesString</a></td><td>StringRef RegExp, Regex::RegexFlags Flags = NoFlags</td></tr>
+<tr><td colspan="4" class="doc" id="matchesString0"><pre>Matches string literals that contain a substring matched by the given RegExp
+
+Example matches "foo" and "foobar" but not "bar"
+  (matcher = stringLiteral(matchesString("foo.*")))
+  const char* a = "foo";
+  const char* b = "foobar";
+  const char* c = "bar";
+
+Usable as: Matcher<StringLiteral>
+</pre></td></tr>
+
+
+
 <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1StringLiteral.html">StringLiteral</a>></td><td class="name" onclick="toggle('hasSize1')"><a name="hasSize1Anchor">hasSize</a></td><td>unsigned N</td></tr>
 <tr><td colspan="4" class="doc" id="hasSize1"><pre>Matches nodes that have the specified size.
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7beef7be0e6a53..760d566eabe9e3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -307,6 +307,8 @@ AST Matchers
 - Fixed an issue with the `hasName` and `hasAnyName` matcher when matching
   inline namespaces with an enclosing namespace of the same name.
 
+Add `matchesString` for `StringLiteral` which matches literals on given `RegExp`.
+
 clang-format
 ------------
 
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index ca44c3ee085654..bff415294c4561 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3116,6 +3116,30 @@ AST_MATCHER_REGEX(NamedDecl, matchesName, RegExp) {
   return RegExp->match(FullNameString);
 }
 
+/// Matches string literals that contain a substring matched by the given RegExp.
+///
+/// Example matches "foo" and "foobar" but not "bar"
+///   (matcher = stringLiteral(matchesString("foo.*")))
+/// \code
+///   const char* a = "foo";
+///   const char* b = "foobar";
+///   const char* c = "bar";
+/// \endcode
+///
+/// Usable as: Matcher<StringLiteral>
+AST_MATCHER_REGEX(StringLiteral, matchesString, RegExp) {
+  constexpr unsigned StringLength = 64;
+  SmallString<StringLength> Str;
+  llvm::raw_svector_ostream OS(Str);
+  Node.outputString(OS);
+  StringRef OSRef = OS.str();
+  if (OSRef.size() < 2U) {
+    return false;
+  }
+  OSRef = OSRef.substr(1, OSRef.size() - 2);
+  return RegExp->match(OSRef);
+}
+
 /// Matches overloaded operator names.
 ///
 /// Matches overloaded operator names specified in strings without the
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 2c75e6beb74301..a3a2515d86be70 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -125,6 +125,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER_OVERLOAD(equals);
 
   REGISTER_REGEX_MATCHER(isExpansionInFileMatching);
+  REGISTER_REGEX_MATCHER(matchesString);
   REGISTER_REGEX_MATCHER(matchesName);
   REGISTER_REGEX_MATCHER(matchesSelector);
 
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 611e1f9ba5327c..ff9684fb54b266 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2503,6 +2503,25 @@ TEST_P(ASTMatchersTest, IsDelegatingConstructor) {
       cxxConstructorDecl(isDelegatingConstructor(), parameterCountIs(1))));
 }
 
+TEST_P(ASTMatchersTest, MatchesString) {
+  StatementMatcher Literal = stringLiteral(matchesString("foo.*"));
+  EXPECT_TRUE(matches("const char* a = \"foo\";", Literal));
+  EXPECT_TRUE(matches("const char* b = \"foobar\";", Literal));
+  EXPECT_TRUE(matches("const char* b = \"fo\"\"obar\";", Literal));
+  EXPECT_TRUE(notMatches("const char* c = \"bar\";", Literal));
+  // test embedded nulls
+  StatementMatcher Literal2 = stringLiteral(matchesString("bar"));
+  EXPECT_TRUE(matches("const char* b = \"foo\\0bar\";", Literal2));
+  EXPECT_TRUE(notMatches("const char* b = \"foo\\0b\\0ar\";", Literal2));
+  // test prefix
+  if (!GetParam().isCXX20OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(matches("const wchar_t* a = L\"foo\";", Literal));
+  EXPECT_TRUE(matches("const char16_t* a = u\"foo\";", Literal));
+  EXPECT_TRUE(matches("const char32_t* a = U\"foo\";", Literal));
+}
+
 TEST_P(ASTMatchersTest, HasSize) {
   StatementMatcher Literal = stringLiteral(hasSize(4));
   EXPECT_TRUE(matches("const char *s = \"abcd\";", Literal));

>From 99e62558a94fa1a1cc311297eb59954b64a11e5c Mon Sep 17 00:00:00 2001
From: hehouhua <hehouhua at feysh.com>
Date: Fri, 9 Aug 2024 11:13:46 +0800
Subject: [PATCH 2/4] test

---
 clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index ff9684fb54b266..4d8b9dc08dc9f5 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2514,9 +2514,6 @@ TEST_P(ASTMatchersTest, MatchesString) {
   EXPECT_TRUE(matches("const char* b = \"foo\\0bar\";", Literal2));
   EXPECT_TRUE(notMatches("const char* b = \"foo\\0b\\0ar\";", Literal2));
   // test prefix
-  if (!GetParam().isCXX20OrLater()) {
-    return;
-  }
   EXPECT_TRUE(matches("const wchar_t* a = L\"foo\";", Literal));
   EXPECT_TRUE(matches("const char16_t* a = u\"foo\";", Literal));
   EXPECT_TRUE(matches("const char32_t* a = U\"foo\";", Literal));

>From 92e7dc2e494bd4bc5ea55a3d92ab1b55df65e9e0 Mon Sep 17 00:00:00 2001
From: hehouhua <hehouhua at feysh.com>
Date: Fri, 9 Aug 2024 11:55:23 +0800
Subject: [PATCH 3/4] test2

---
 .../unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 4d8b9dc08dc9f5..3d045ec0ef4d8e 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2515,8 +2515,14 @@ TEST_P(ASTMatchersTest, MatchesString) {
   EXPECT_TRUE(notMatches("const char* b = \"foo\\0b\\0ar\";", Literal2));
   // test prefix
   EXPECT_TRUE(matches("const wchar_t* a = L\"foo\";", Literal));
-  EXPECT_TRUE(matches("const char16_t* a = u\"foo\";", Literal));
-  EXPECT_TRUE(matches("const char32_t* a = U\"foo\";", Literal));
+}
+
+TEST(MatchesString, MatchesStringPrefixed) {
+  StatementMatcher Literal = stringLiteral(matchesString("foo.*"));
+  EXPECT_TRUE(matchesConditionally("const char16_t* a = u\"foo\";", Literal,
+                                   true, {"-std=c++11"}));
+  EXPECT_TRUE(matchesConditionally("const char32_t* a = U\"foo\";", Literal,
+                                   true, {"-std=c++11"}));
 }
 
 TEST_P(ASTMatchersTest, HasSize) {

>From 52d07426745ba70bd2b3776b10be087eceedbf52 Mon Sep 17 00:00:00 2001
From: hehouhua <hehouhua at feysh.com>
Date: Fri, 9 Aug 2024 13:42:32 +0800
Subject: [PATCH 4/4] test3

---
 clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 3d045ec0ef4d8e..5a569427e5ca35 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2513,8 +2513,6 @@ TEST_P(ASTMatchersTest, MatchesString) {
   StatementMatcher Literal2 = stringLiteral(matchesString("bar"));
   EXPECT_TRUE(matches("const char* b = \"foo\\0bar\";", Literal2));
   EXPECT_TRUE(notMatches("const char* b = \"foo\\0b\\0ar\";", Literal2));
-  // test prefix
-  EXPECT_TRUE(matches("const wchar_t* a = L\"foo\";", Literal));
 }
 
 TEST(MatchesString, MatchesStringPrefixed) {
@@ -2523,6 +2521,8 @@ TEST(MatchesString, MatchesStringPrefixed) {
                                    true, {"-std=c++11"}));
   EXPECT_TRUE(matchesConditionally("const char32_t* a = U\"foo\";", Literal,
                                    true, {"-std=c++11"}));
+  EXPECT_TRUE(matchesConditionally("const char32_t* a = U\"foo\";", Literal,
+                                   true, {"-std=c++11"}));
 }
 
 TEST_P(ASTMatchersTest, HasSize) {



More information about the cfe-commits mailing list