forked from OSchip/llvm-project
[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 llvm-svn: 363855
This commit is contained in:
parent
61d7e35b22
commit
e1f4ba85e5
|
@ -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(isDelegatingConstructor()) will match #3 and #4, but not
|
|||
|
||||
|
||||
<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
|
||||
explicit(false) S(bool) // # 7
|
||||
explicit(true) S(char) // # 8
|
||||
explicit(b) S(S) // # 9
|
||||
};
|
||||
cxxConstructorDecl(isExplicit()) will match #2, but not #1.
|
||||
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()) will match #3, but not #1 or #2.
|
|||
|
||||
|
||||
<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
|
||||
explicit(false) S(bool) // # 7
|
||||
explicit(true) S(char) // # 8
|
||||
explicit(b) S(S) // # 9
|
||||
};
|
||||
cxxConstructorDecl(isExplicit()) will match #2, but not #1.
|
||||
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(hasAnyConstructorInitializer(isWritten()))
|
|||
</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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1138,6 +1138,17 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl>
|
|||
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, isDelegatingConstructor) {
|
|||
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.
|
||||
///
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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; };",
|
||||
|
|
Loading…
Reference in New Issue