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:
Benjamin Kramer 2014-09-03 12:08:14 +00:00
parent 8c90fd71f7
commit 7ab8476c15
3 changed files with 98 additions and 0 deletions

View File

@ -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.
///

View File

@ -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);

View File

@ -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(