r217029 - ASTMatchers: Add a matcher to detect whether a decl or stmt is inside a template instantiation.
Benjamin Kramer
benny.kra at googlemail.com
Wed Sep 3 05:08:15 PDT 2014
Author: d0k
Date: Wed Sep 3 07:08:14 2014
New Revision: 217029
URL: http://llvm.org/viewvc/llvm-project?rev=217029&view=rev
Log:
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
Modified:
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=217029&r1=217028&r2=217029&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Wed Sep 3 07:08:14 2014
@@ -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.
///
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=217029&r1=217028&r2=217029&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Wed Sep 3 07:08:14 2014
@@ -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);
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=217029&r1=217028&r2=217029&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Wed Sep 3 07:08:14 2014
@@ -3504,6 +3504,62 @@ TEST(IsTemplateInstantiation, DoesNotMat
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(
More information about the cfe-commits
mailing list