Tyker created this revision.
Tyker added a reviewer: klimek.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Changes:

- add an ast matcher for deductiong guide.
- allow isExplicit matcher for deductiong guide.
- add hasExplicitSpecifier matcher which matches for declarations that have an 
explicit specifier even if it is unresolved or resolved to false.
- added test for all of the above.


Repository:
  rC Clang

https://reviews.llvm.org/D61552

Files:
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -810,6 +810,31 @@
                       cxxConversionDecl(isExplicit())));
   EXPECT_TRUE(notMatches("struct S { operator int(); };",
                          cxxConversionDecl(isExplicit())));
+  EXPECT_TRUE(matchesConditionally(
+      "template<bool b> struct S { explicit(b) operator int(); };",
+      cxxConversionDecl(isExplicit()), false, "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally(
+      "struct S { explicit(true) operator int(); };",
+      cxxConversionDecl(isExplicit()), true, "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally(
+      "struct S { explicit(false) operator int(); };",
+      cxxConversionDecl(isExplicit()), false, "-std=c++2a"));
+}
+
+TEST(ConversionDeclaration, HasExplicitSpecifier) {
+  EXPECT_TRUE(matches("struct S { explicit operator int(); };",
+                      cxxConversionDecl(hasExplicitSpecifier())));
+  EXPECT_TRUE(notMatches("struct S { operator int(); };",
+                         cxxConversionDecl(hasExplicitSpecifier())));
+  EXPECT_TRUE(matchesConditionally(
+      "template<bool b> struct S { explicit(b) operator int(); };",
+      cxxConversionDecl(hasExplicitSpecifier()), true, "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally(
+      "struct S { explicit(true) operator int(); };",
+      cxxConversionDecl(hasExplicitSpecifier()), true, "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally(
+      "struct S { explicit(false) operator int(); };",
+      cxxConversionDecl(hasExplicitSpecifier()), true, "-std=c++2a"));
 }
 
 TEST(Matcher, ArgumentCount) {
@@ -1129,6 +1154,77 @@
                       cxxConstructorDecl(isExplicit())));
   EXPECT_TRUE(notMatches("struct S { S(int); };",
                          cxxConstructorDecl(isExplicit())));
+  EXPECT_TRUE(matchesConditionally(
+      "template<bool b> struct S { explicit(b) S(int);};",
+      cxxConstructorDecl(isExplicit()), false, "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally("struct S { explicit(true) S(int);};",
+                                   cxxConstructorDecl(isExplicit()), true,
+                                   "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally("struct S { explicit(false) S(int);};",
+                                   cxxConstructorDecl(isExplicit()), false,
+                                   "-std=c++2a"));
+}
+
+TEST(ConstructorDeclaration, HasExplicitSpecifier) {
+  EXPECT_TRUE(matches("struct S { explicit S(int); };",
+                      cxxConstructorDecl(hasExplicitSpecifier())));
+  EXPECT_TRUE(notMatches("struct S { S(int); };",
+                         cxxConstructorDecl(hasExplicitSpecifier())));
+  EXPECT_TRUE(matchesConditionally(
+      "template<bool b> struct S { explicit(b) S(int);};",
+      cxxConstructorDecl(hasExplicitSpecifier()), true, "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally("struct S { explicit(true) S(int);};",
+                                   cxxConstructorDecl(hasExplicitSpecifier()),
+                                   true, "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally("struct S { explicit(false) S(int);};",
+                                   cxxConstructorDecl(hasExplicitSpecifier()),
+                                   true, "-std=c++2a"));
+}
+
+TEST(DeductionGuideDeclaration, IsExplicit) {
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(isExplicit()), false,
+                                   "-std=c++17"));
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "explicit S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(isExplicit()), true,
+                                   "-std=c++17"));
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "explicit(true) S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(isExplicit()), true,
+                                   "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "explicit(false) S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(isExplicit()), false,
+                                   "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "template<bool b = true> explicit(b) S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(isExplicit()), false,
+                                   "-std=c++2a"));
+}
+
+TEST(DeductionGuideDeclaration, HasExplicitSpecifier) {
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(hasExplicitSpecifier()), false,
+                                   "-std=c++17"));
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "explicit S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(hasExplicitSpecifier()), true,
+                                   "-std=c++17"));
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "explicit(true) S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(hasExplicitSpecifier()), true,
+                                   "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "explicit(false) S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(hasExplicitSpecifier()), true,
+                                   "-std=c++2a"));
+  EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+                                   "template<bool b = true> explicit(b) S(int) -> S<int>;",
+                                   cxxDeductionGuideDecl(hasExplicitSpecifier()), true,
+                                   "-std=c++2a"));
 }
 
 TEST(ConstructorDeclaration, Kinds) {
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -168,6 +168,7 @@
   REGISTER_MATCHER(cxxConstructExpr);
   REGISTER_MATCHER(cxxConstructorDecl);
   REGISTER_MATCHER(cxxConversionDecl);
+  REGISTER_MATCHER(cxxDeductionGuideDecl);
   REGISTER_MATCHER(cxxCtorInitializer);
   REGISTER_MATCHER(cxxDefaultArgExpr);
   REGISTER_MATCHER(cxxDeleteExpr);
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -1138,6 +1138,17 @@
 extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl>
     cxxConversionDecl;
 
+/// Matches deduction guide declarations.
+///
+/// Example matches the deduction guide.
+/// \code
+///   template<typename T>
+///   class X { X(int) };
+///   X(int) -> X<int>;
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXDeductionGuideDecl>
+    cxxDeductionGuideDecl;
+
 /// Matches variable declarations.
 ///
 /// Note: this does not match declarations of member variables, which are
@@ -6154,29 +6165,63 @@
   return Node.isDelegatingConstructor();
 }
 
-/// Matches constructor and conversion declarations that are marked with
-/// the explicit keyword.
+/// Matches constructor, conversion function and deduction guide declarations
+/// that have an explicit specifier if this explicit specifier is resolved to
+/// true.
 ///
 /// Given
 /// \code
+///   template<bool b>
 ///   struct S {
 ///     S(int); // #1
 ///     explicit S(double); // #2
 ///     operator int(); // #3
 ///     explicit operator bool(); // #4
+///     explicit(false) S(bool) // # 7
+///     explicit(true) S(char) // # 8
+///     explicit(b) S(S) // # 9
 ///   };
+///   S(int) -> S<true> // #5
+///   explicit S(double) -> S<false> // #6
 /// \endcode
 /// cxxConstructorDecl(isExplicit()) will match #2, but not #1.
 /// cxxConversionDecl(isExplicit()) will match #4, but not #3.
-AST_POLYMORPHIC_MATCHER(isExplicit,
-                        AST_POLYMORPHIC_SUPPORTED_TYPES(CXXConstructorDecl,
-                                                        CXXConversionDecl)) {
-  // FIXME : it's not clear whether this should match a dependent
-  //         explicit(....). this matcher should also be able to match
-  //         CXXDeductionGuideDecl with explicit specifier.
+/// cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5.
+/// cxxConstructorDecl(isExplicit()) will match #8, but not #7 or #9.
+AST_POLYMORPHIC_MATCHER(isExplicit, AST_POLYMORPHIC_SUPPORTED_TYPES(
+                                        CXXConstructorDecl, CXXConversionDecl,
+                                        CXXDeductionGuideDecl)) {
   return Node.isExplicit();
 }
 
+/// Matches constructor, conversion function and deduction guide declarations
+/// that have an explicit specifier.
+///
+/// Given
+/// \code
+///   template<bool b>
+///   struct S {
+///     S(int); // #1
+///     explicit S(double); // #2
+///     operator int(); // #3
+///     explicit operator bool(); // #4
+///     explicit(false) S(bool) // # 7
+///     explicit(true) S(char) // # 8
+///     explicit(b) S(S) // # 9
+///   };
+///   S(int) -> S<true> // #5
+///   explicit S(double) -> S<false> // #6
+/// \endcode
+/// cxxConstructorDecl(isExplicit()) will match #2, #7, #8 and #9, but not #1.
+/// cxxConversionDecl(isExplicit()) will match #4, but not #3.
+/// cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5.
+AST_POLYMORPHIC_MATCHER(
+    hasExplicitSpecifier,
+    AST_POLYMORPHIC_SUPPORTED_TYPES(CXXConstructorDecl, CXXConversionDecl,
+                                    CXXDeductionGuideDecl)) {
+  return Node.getExplicitSpecifier().isSpecified();
+}
+
 /// Matches function and namespace declarations that are marked with
 /// the inline keyword.
 ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D61552: [... Tyker via Phabricator via cfe-commits

Reply via email to