From: Etienne Bergeron Date: Thu, 12 May 2016 04:20:04 +0000 (+0000) Subject: Add an AST matcher for string-literal length X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0840ba9a188d5db49419c4672f14d3f2096c328b;p=clang Add an AST matcher for string-literal length Summary: This patch is adding support for a matcher to check string literal length. This matcher is used in clang-tidy checkers and is part of this refactoring: see: http://reviews.llvm.org/D19841 Reviewers: sbenza, klimek, aaron.ballman Subscribers: alexfh, klimek, cfe-commits Differential Revision: http://reviews.llvm.org/D19876 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@269274 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index bd0f53f5b1..2d4b8c1999 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -644,7 +644,8 @@ Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral), though. Example matches 'a', L'a' - char ch = 'a'; wchar_t chw = L'a'; + char ch = 'a'; + wchar_t chw = L'a'; @@ -652,7 +653,8 @@ Example matches 'a', L'a'
Matches compound (i.e. non-scalar) literals
 
 Example match: {1}, (1, 2)
-  int array[4] = {1}; vector int myvec = (vector int)(1, 2);
+  int array[4] = {1};
+  vector int myvec = (vector int)(1, 2);
 
@@ -1217,7 +1219,8 @@ Example match: ({ int X = 4; X; })
Matches string literals (also matches wide string literals).
 
 Example matches "abcd", L"abcd"
-  char *s = "abcd"; wchar_t *ws = L"abcd"
+  char *s = "abcd";
+  wchar_t *ws = L"abcd";
 
@@ -2191,14 +2194,19 @@ compoundStmt(statementCountIs(0))) Matcher<ConstantArrayType>hasSizeunsigned N -
Matches ConstantArrayType nodes that have the specified size.
+
Matches nodes that have the specified size.
 
 Given
   int a[42];
   int b[2 * 21];
   int c[41], d[43];
+  char *s = "abcd";
+  wchar_t *ws = L"abcd";
+  char *w = "a";
 constantArrayType(hasSize(42))
   matches "int a[42]" and "int b[2 * 21]"
+stringLiteral(hasSize(4))
+  matches "abcd", L"abcd"
 
@@ -2955,6 +2963,23 @@ Usable as: Matcher<StringLiteral>hasSizeunsigned N +
Matches nodes that have the specified size.
+
+Given
+  int a[42];
+  int b[2 * 21];
+  int c[41], d[43];
+  char *s = "abcd";
+  wchar_t *ws = L"abcd";
+  char *w = "a";
+constantArrayType(hasSize(42))
+  matches "int a[42]" and "int b[2 * 21]"
+stringLiteral(hasSize(4))
+  matches "abcd", L"abcd"
+
+ + Matcher<TagDecl>isDefinition
Matches if a declaration has a body attached.
 
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 300dca9ff5..74206b9a5c 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1560,7 +1560,8 @@ const internal::VariadicDynCastAllOfMatcher<
 ///
 /// 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 @@ const internal::VariadicDynCastAllOfMatcher<
 ///
 /// 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 @@ const internal::VariadicDynCastAllOfMatcher<
 ///
 /// 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 @@ AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement,
 ///   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.
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 4b986c5325..af8d737ad9 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1650,6 +1650,19 @@ inline const Stmt *GetBodyMatcher::get(const FunctionDecl &Node) {
   return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
 }
 
+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) {
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index adf3b27cb1..34eca9977a 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -51,7 +51,6 @@ TEST(Finder, DynamicOnlyAcceptsSomeMatchers) {
 
   // 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 @@ TEST(Matcher, StringLiterals) {
   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));