ASTMatchers: Add a matcher to detect whether a decl or stmt is inside a template instantiation.
This is hoisted from clang-tidy where it's used everywhere. The implementation is not particularly efficient right now, but there is no easy fix for that. Differential Revision: http://reviews.llvm.org/D5085 llvm-svn: 217029
This commit is contained in:
parent
8c90fd71f7
commit
7ab8476c15
|
@ -2967,6 +2967,46 @@ AST_POLYMORPHIC_MATCHER(
|
|||
TSK_ExplicitInstantiationDefinition);
|
||||
}
|
||||
|
||||
/// \brief Matches declarations that are template instantiations or are inside
|
||||
/// template instantiations.
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
/// template<typename T> void A(T t) { T i; }
|
||||
/// A(0);
|
||||
/// A(0U);
|
||||
/// \endcode
|
||||
/// functionDecl(isInstantiated())
|
||||
/// matches 'A(int) {...};' and 'A(unsigned) {...}'.
|
||||
AST_MATCHER(Decl, isInstantiated) {
|
||||
auto IsInstantiation = decl(anyOf(recordDecl(isTemplateInstantiation()),
|
||||
functionDecl(isTemplateInstantiation())));
|
||||
auto InnerMatcher =
|
||||
decl(anyOf(IsInstantiation, hasAncestor(IsInstantiation)));
|
||||
return InnerMatcher.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Matches statements inside of a template instantiation.
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
/// int j;
|
||||
/// template<typename T> void A(T t) { T i; j += 42;}
|
||||
/// A(0);
|
||||
/// A(0U);
|
||||
/// \endcode
|
||||
/// declStmt(isInTemplateInstantiation())
|
||||
/// matches 'int i;' and 'unsigned i'.
|
||||
/// unless(stmt(isInTemplateInstantiation()))
|
||||
/// will NOT match j += 42; as it's shared between the template definition and
|
||||
/// instantiation.
|
||||
AST_MATCHER(Stmt, isInTemplateInstantiation) {
|
||||
auto InnerMatcher =
|
||||
stmt(hasAncestor(decl(anyOf(recordDecl(isTemplateInstantiation()),
|
||||
functionDecl(isTemplateInstantiation())))));
|
||||
return InnerMatcher.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Matches explicit template specializations of function, class, or
|
||||
/// static member variable template instantiations.
|
||||
///
|
||||
|
|
|
@ -241,7 +241,9 @@ RegistryMaps::RegistryMaps() {
|
|||
REGISTER_MATCHER(isExpr);
|
||||
REGISTER_MATCHER(isExternC);
|
||||
REGISTER_MATCHER(isImplicit);
|
||||
REGISTER_MATCHER(isInstantiated);
|
||||
REGISTER_MATCHER(isInteger);
|
||||
REGISTER_MATCHER(isInTemplateInstantiation);
|
||||
REGISTER_MATCHER(isListInitialization);
|
||||
REGISTER_MATCHER(isOverride);
|
||||
REGISTER_MATCHER(isPrivate);
|
||||
|
|
|
@ -3504,6 +3504,62 @@ TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) {
|
|||
recordDecl(isTemplateInstantiation())));
|
||||
}
|
||||
|
||||
TEST(IsInstantiated, MatchesInstantiation) {
|
||||
EXPECT_TRUE(
|
||||
matches("template<typename T> class A { T i; }; class Y { A<int> a; };",
|
||||
recordDecl(isInstantiated())));
|
||||
}
|
||||
|
||||
TEST(IsInstantiated, NotMatchesDefinition) {
|
||||
EXPECT_TRUE(notMatches("template<typename T> class A { T i; };",
|
||||
recordDecl(isInstantiated())));
|
||||
}
|
||||
|
||||
TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) {
|
||||
EXPECT_TRUE(matches("template<typename T> struct A { A() { T i; } };"
|
||||
"class Y { A<int> a; }; Y y;",
|
||||
declStmt(isInTemplateInstantiation())));
|
||||
}
|
||||
|
||||
TEST(IsInTemplateInstantiation, NotMatchesDefinitionStmt) {
|
||||
EXPECT_TRUE(notMatches("template<typename T> struct A { void x() { T i; } };",
|
||||
declStmt(isInTemplateInstantiation())));
|
||||
}
|
||||
|
||||
TEST(IsInstantiated, MatchesFunctionInstantiation) {
|
||||
EXPECT_TRUE(
|
||||
matches("template<typename T> void A(T t) { T i; } void x() { A(0); }",
|
||||
functionDecl(isInstantiated())));
|
||||
}
|
||||
|
||||
TEST(IsInstantiated, NotMatchesFunctionDefinition) {
|
||||
EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }",
|
||||
varDecl(isInstantiated())));
|
||||
}
|
||||
|
||||
TEST(IsInTemplateInstantiation, MatchesFunctionInstantiationStmt) {
|
||||
EXPECT_TRUE(
|
||||
matches("template<typename T> void A(T t) { T i; } void x() { A(0); }",
|
||||
declStmt(isInTemplateInstantiation())));
|
||||
}
|
||||
|
||||
TEST(IsInTemplateInstantiation, NotMatchesFunctionDefinitionStmt) {
|
||||
EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }",
|
||||
declStmt(isInTemplateInstantiation())));
|
||||
}
|
||||
|
||||
TEST(IsInTemplateInstantiation, Sharing) {
|
||||
auto Matcher = binaryOperator(unless(isInTemplateInstantiation()));
|
||||
// FIXME: Node sharing is an implementation detail, exposing it is ugly
|
||||
// and makes the matcher behave in non-obvious ways.
|
||||
EXPECT_TRUE(notMatches(
|
||||
"int j; template<typename T> void A(T t) { j += 42; } void x() { A(0); }",
|
||||
Matcher));
|
||||
EXPECT_TRUE(matches(
|
||||
"int j; template<typename T> void A(T t) { j += t; } void x() { A(0); }",
|
||||
Matcher));
|
||||
}
|
||||
|
||||
TEST(IsExplicitTemplateSpecialization,
|
||||
DoesNotMatchPrimaryTemplate) {
|
||||
EXPECT_TRUE(notMatches(
|
||||
|
|
Loading…
Reference in New Issue