Author: tyker Date: Wed Jun 19 11:27:56 2019 New Revision: 363855 URL: http://llvm.org/viewvc/llvm-project?rev=363855&view=rev Log: [clang] Adapt ASTMatcher to explicit(bool) specifier
Summary: Changes: - add an ast matcher for deductiong guide. - allow isExplicit matcher for deductiong guide. - add hasExplicitSpecifier matcher which give access to the expression of the explicit specifier if present. Reviewers: klimek, rsmith, aaron.ballman Reviewed By: aaron.ballman Subscribers: aaron.ballman, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D61552 Modified: cfe/trunk/docs/LibASTMatchersReference.html cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Modified: cfe/trunk/docs/LibASTMatchersReference.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=363855&r1=363854&r2=363855&view=diff ============================================================================== --- cfe/trunk/docs/LibASTMatchersReference.html (original) +++ cfe/trunk/docs/LibASTMatchersReference.html Wed Jun 19 11:27:56 2019 @@ -194,6 +194,16 @@ Example matches the operator. </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxDeductionGuideDecl0')"><a name="cxxDeductionGuideDecl0Anchor">cxxDeductionGuideDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDeductionGuideDecl.html">CXXDeductionGuideDecl</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="cxxDeductionGuideDecl0"><pre>Matches user-defined and implicitly generated deduction guide. + +Example matches the deduction guide. + template<typename T> + class X { X(int) }; + X(int) -> X<int>; +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('cxxDestructorDecl0')"><a name="cxxDestructorDecl0Anchor">cxxDestructorDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDestructorDecl.html">CXXDestructorDecl</a>>...</td></tr> <tr><td colspan="4" class="doc" id="cxxDestructorDecl0"><pre>Matches explicit C++ destructor declarations. @@ -2222,18 +2232,26 @@ cxxConstructorDecl(isDelegatingConstruct <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>></td><td class="name" onclick="toggle('isExplicit0')"><a name="isExplicit0Anchor">isExplicit</a></td><td></td></tr> -<tr><td colspan="4" class="doc" id="isExplicit0"><pre>Matches constructor and conversion declarations that are marked with -the explicit keyword. +<tr><td colspan="4" class="doc" id="isExplicit0"><pre>Matches constructor, conversion function, and deduction guide declarations +that have an explicit specifier if this explicit specifier is resolved to +true. Given + template<bool b> struct S { S(int); // #1 explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - }; -cxxConstructorDecl(isExplicit()) will match #2, but not #1. + 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 +cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. cxxConversionDecl(isExplicit()) will match #4, but not #3. +cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. </pre></td></tr> @@ -2251,18 +2269,26 @@ cxxConstructorDecl(isMoveConstructor()) <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConversionDecl.html">CXXConversionDecl</a>></td><td class="name" onclick="toggle('isExplicit1')"><a name="isExplicit1Anchor">isExplicit</a></td><td></td></tr> -<tr><td colspan="4" class="doc" id="isExplicit1"><pre>Matches constructor and conversion declarations that are marked with -the explicit keyword. +<tr><td colspan="4" class="doc" id="isExplicit1"><pre>Matches constructor, conversion function, and deduction guide declarations +that have an explicit specifier if this explicit specifier is resolved to +true. Given + template<bool b> struct S { S(int); // #1 explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - }; -cxxConstructorDecl(isExplicit()) will match #2, but not #1. + 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 +cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. cxxConversionDecl(isExplicit()) will match #4, but not #3. +cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. </pre></td></tr> @@ -2317,6 +2343,30 @@ cxxConstructorDecl(hasAnyConstructorInit </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDeductionGuideDecl.html">CXXDeductionGuideDecl</a>></td><td class="name" onclick="toggle('isExplicit2')"><a name="isExplicit2Anchor">isExplicit</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isExplicit2"><pre>Matches constructor, conversion function, and deduction guide declarations +that have an explicit specifier if this explicit specifier is resolved to +true. + +Given + 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 +cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. +cxxConversionDecl(isExplicit()) will match #4, but not #3. +cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDependentScopeMemberExpr.html">CXXDependentScopeMemberExpr</a>></td><td class="name" onclick="toggle('isArrow2')"><a name="isArrow2Anchor">isArrow</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isArrow2"><pre>Matches member expressions that are called with '->' as opposed to '.'. @@ -6007,6 +6057,29 @@ with compoundStmt() </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasExplicitSpecifier0')"><a name="hasExplicitSpecifier0Anchor">hasExplicitSpecifier</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasExplicitSpecifier0"><pre>Matches the expression in an explicit specifier if present in the given +declaration. + +Given + 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 +cxxConstructorDecl(hasExplicitSpecifier(constantExpr())) will match #7, #8 and #9, but not #1 or #2. +cxxConversionDecl(hasExplicitSpecifier(constantExpr())) will not match #3 or #4. +cxxDeductionGuideDecl(hasExplicitSpecifier(constantExpr())) will not match #5 or #6. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasParameter0')"><a name="hasParameter0Anchor">hasParameter</a></td><td>unsigned N, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasParameter0"><pre>Matches the n'th parameter of a function or an ObjC method declaration or a block. Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=363855&r1=363854&r2=363855&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Jun 19 11:27:56 2019 @@ -2033,6 +2033,9 @@ public: // if the given declaration has no explicit. the returned explicit specifier // is defaulted. .isSpecified() will be false. static ExplicitSpecifier getFromDecl(FunctionDecl *Function); + static const ExplicitSpecifier getFromDecl(const FunctionDecl *Function) { + return getFromDecl(const_cast<FunctionDecl *>(Function)); + } static ExplicitSpecifier Invalid() { return ExplicitSpecifier(nullptr, ExplicitSpecKind::Unresolved); } Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=363855&r1=363854&r2=363855&view=diff ============================================================================== --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original) +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Wed Jun 19 11:27:56 2019 @@ -1138,6 +1138,17 @@ extern const internal::VariadicDynCastAl extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl> cxxConversionDecl; +/// Matches user-defined and implicitly generated deduction guide. +/// +/// 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 @@ AST_MATCHER(CXXConstructorDecl, isDelega 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. +/// cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. /// 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. +AST_POLYMORPHIC_MATCHER(isExplicit, AST_POLYMORPHIC_SUPPORTED_TYPES( + CXXConstructorDecl, CXXConversionDecl, + CXXDeductionGuideDecl)) { return Node.isExplicit(); } +/// Matches the expression in an explicit specifier if present in the given +/// declaration. +/// +/// 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(hasExplicitSpecifier(constantExpr())) will match #7, #8 and #9, but not #1 or #2. +/// cxxConversionDecl(hasExplicitSpecifier(constantExpr())) will not match #3 or #4. +/// cxxDeductionGuideDecl(hasExplicitSpecifier(constantExpr())) will not match #5 or #6. +AST_MATCHER_P(FunctionDecl, hasExplicitSpecifier, internal::Matcher<Expr>, + InnerMatcher) { + ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(&Node); + if (!ES.getExpr()) + return false; + return InnerMatcher.matches(*ES.getExpr(), Finder, Builder); +} + /// Matches function and namespace declarations that are marked with /// the inline keyword. /// Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=363855&r1=363854&r2=363855&view=diff ============================================================================== --- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original) +++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Wed Jun 19 11:27:56 2019 @@ -169,6 +169,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(cxxConstructorDecl); REGISTER_MATCHER(cxxConversionDecl); REGISTER_MATCHER(cxxCtorInitializer); + REGISTER_MATCHER(cxxDeductionGuideDecl); REGISTER_MATCHER(cxxDefaultArgExpr); REGISTER_MATCHER(cxxDeleteExpr); REGISTER_MATCHER(cxxDependentScopeMemberExpr); @@ -267,6 +268,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasEitherOperand); REGISTER_MATCHER(hasElementType); REGISTER_MATCHER(hasElse); + REGISTER_MATCHER(hasExplicitSpecifier); REGISTER_MATCHER(hasExternalFormalLinkage); REGISTER_MATCHER(hasFalseExpression); REGISTER_MATCHER(hasGlobalStorage); Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=363855&r1=363854&r2=363855&view=diff ============================================================================== --- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (original) +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Wed Jun 19 11:27:56 2019 @@ -878,6 +878,15 @@ TEST(ConversionDeclaration, IsExplicit) 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(Matcher, ArgumentCount) { @@ -1197,6 +1206,38 @@ TEST(ConstructorDeclaration, IsExplicit) 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(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(ConstructorDeclaration, Kinds) { Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp?rev=363855&r1=363854&r2=363855&view=diff ============================================================================== --- cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp (original) +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Wed Jun 19 11:27:56 2019 @@ -1735,6 +1735,56 @@ TEST(SwitchCase, MatchesEachCase) { llvm::make_unique<VerifyIdIsBoundTo<CaseStmt>>("x", 3))); } +TEST(Declaration, HasExplicitSpecifier) { + EXPECT_TRUE(matchesConditionally( + "void f();", functionDecl(hasExplicitSpecifier(constantExpr())), false, + "-std=c++2a")); + EXPECT_TRUE(matchesConditionally( + "template<bool b> struct S { explicit operator int(); };", + cxxConversionDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), + false, "-std=c++2a")); + EXPECT_TRUE(matchesConditionally( + "template<bool b> struct S { explicit(b) operator int(); };", + cxxConversionDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), + false, "-std=c++2a")); + EXPECT_TRUE(matchesConditionally( + "struct S { explicit(true) operator int(); };", + cxxConversionDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), + true, "-std=c++2a")); + EXPECT_TRUE(matchesConditionally( + "struct S { explicit(false) operator int(); };", + cxxConversionDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), + true, "-std=c++2a")); + EXPECT_TRUE(matchesConditionally( + "template<bool b> struct S { explicit(b) S(int); };", + cxxConstructorDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), + false, "-std=c++2a")); + EXPECT_TRUE(matchesConditionally( + "struct S { explicit(true) S(int); };", + cxxConstructorDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), + true, "-std=c++2a")); + EXPECT_TRUE(matchesConditionally( + "struct S { explicit(false) S(int); };", + cxxConstructorDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), + 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(constantExpr(has(cxxBoolLiteral())))), + false, "-std=c++2a")); + EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int); };" + "explicit(true) S(int) -> S<int>;", + cxxDeductionGuideDecl(hasExplicitSpecifier( + constantExpr(has(cxxBoolLiteral())))), + true, "-std=c++2a")); + EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int); };" + "explicit(false) S(int) -> S<int>;", + cxxDeductionGuideDecl(hasExplicitSpecifier( + constantExpr(has(cxxBoolLiteral())))), + true, "-std=c++2a")); +} + TEST(ForEachConstructorInitializer, MatchesInitializers) { EXPECT_TRUE(matches( "struct X { X() : i(42), j(42) {} int i, j; };", _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits