r363855 - [clang] Adapt ASTMatcher to explicit(bool) specifier
Gauthier Harnisch via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 19 11:27:56 PDT 2019
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; };",
More information about the cfe-commits
mailing list