https://github.com/Gitspike updated https://github.com/llvm/llvm-project/pull/102152
>From f2c760d6fa9ff685584dcb4aa38ae88fee892895 Mon Sep 17 00:00:00 2001 From: hehouhua <hehou...@feysh.com> Date: Wed, 7 Aug 2024 11:55:30 +0800 Subject: [PATCH] [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 ffdb5f8f5af3ed..826ec64e1baca6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -296,6 +296,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)); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits