Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -1560,7 +1560,8 @@ /// /// Example matches "abcd", L"abcd" /// \code -/// char *s = "abcd"; wchar_t *ws = L"abcd" +/// char *s = "abcd"; +/// wchar_t *ws = L"abcd"; /// \endcode const internal::VariadicDynCastAllOfMatcher< Stmt, @@ -1573,7 +1574,8 @@ /// /// Example matches 'a', L'a' /// \code -/// char ch = 'a'; wchar_t chw = L'a'; +/// char ch = 'a'; +/// wchar_t chw = L'a'; /// \endcode const internal::VariadicDynCastAllOfMatcher< Stmt, @@ -1609,7 +1611,8 @@ /// /// Example match: {1}, (1, 2) /// \code -/// int array[4] = {1}; vector int myvec = (vector int)(1, 2); +/// int array[4] = {1}; +/// vector int myvec = (vector int)(1, 2); /// \endcode const internal::VariadicDynCastAllOfMatcher< Stmt, @@ -4228,18 +4231,26 @@ /// matches "int a[2]" AST_TYPE_MATCHER(ConstantArrayType, constantArrayType); -/// \brief Matches \c ConstantArrayType nodes that have the specified size. +/// \brief Matches nodes that have the specified size. /// /// Given /// \code /// int a[42]; /// int b[2 * 21]; /// int c[41], d[43]; +/// char *s = "abcd"; +/// wchar_t *ws = L"abcd"; +/// char *w = "a"; /// \endcode /// constantArrayType(hasSize(42)) /// matches "int a[42]" and "int b[2 * 21]" -AST_MATCHER_P(ConstantArrayType, hasSize, unsigned, N) { - return Node.getSize() == N; +/// stringLiteral(hasSize(4)) +/// matches "abcd", L"abcd" +AST_POLYMORPHIC_MATCHER_P(hasSize, + AST_POLYMORPHIC_SUPPORTED_TYPES(ConstantArrayType, + StringLiteral), + unsigned, N) { + return internal::HasSizeMatcher::hasSize(Node, N); } /// \brief Matches C++ arrays whose size is a value-dependent expression. Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1651,6 +1651,19 @@ } template +struct HasSizeMatcher { + static bool hasSize(const Ty &Node, unsigned int N) { + return Node.getSize() == N; + } +}; + +template <> +inline bool HasSizeMatcher::hasSize( + const StringLiteral &Node, unsigned int N) { + return Node.getLength() == N; +} + +template struct GetSourceExpressionMatcher { static const Expr *get(const Ty &Node) { return Node.getSubExpr(); Index: unittests/ASTMatchers/ASTMatchersTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTest.cpp +++ unittests/ASTMatchers/ASTMatchersTest.cpp @@ -51,7 +51,6 @@ // Do not accept non-toplevel matchers. EXPECT_FALSE(Finder.addDynamicMatcher(isArrow(), nullptr)); - EXPECT_FALSE(Finder.addDynamicMatcher(hasSize(2), nullptr)); EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), nullptr)); } @@ -2536,6 +2535,17 @@ EXPECT_TRUE(notMatches("const char s[1] = {'a'};", Literal)); } +TEST(StringLiteral, HasSize) { + StatementMatcher Literal = stringLiteral(hasSize(4)); + EXPECT_TRUE(matches("const char *s = \"abcd\";", Literal)); + // wide string + EXPECT_TRUE(matches("const wchar_t *s = L\"abcd\";", Literal)); + // with escaped characters + EXPECT_TRUE(matches("const char *s = \"\x05\x06\x07\x08\";", Literal)); + // no matching, too small + EXPECT_TRUE(notMatches("const char *s = \"ab\";", Literal)); +} + TEST(Matcher, CharacterLiterals) { StatementMatcher CharLiteral = characterLiteral(); EXPECT_TRUE(matches("const char c = 'c';", CharLiteral));