From: Benjamin Kramer Date: Wed, 3 Sep 2014 12:08:14 +0000 (+0000) Subject: ASTMatchers: Add a matcher to detect whether a decl or stmt is inside a template... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=29342edf5e3237b9880d5ab891d9a030c0d64c8e;p=clang 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@217029 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 817d325075..b010dd5936 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -2967,6 +2967,46 @@ AST_POLYMORPHIC_MATCHER( TSK_ExplicitInstantiationDefinition); } +/// \brief Matches declarations that are template instantiations or are inside +/// template instantiations. +/// +/// Given +/// \code +/// template 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 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. /// diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 8d58021427..9fb72e6d5e 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -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); diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index 9263736fef..3fbe896a87 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -3504,6 +3504,62 @@ TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) { recordDecl(isTemplateInstantiation()))); } +TEST(IsInstantiated, MatchesInstantiation) { + EXPECT_TRUE( + matches("template class A { T i; }; class Y { A a; };", + recordDecl(isInstantiated()))); +} + +TEST(IsInstantiated, NotMatchesDefinition) { + EXPECT_TRUE(notMatches("template class A { T i; };", + recordDecl(isInstantiated()))); +} + +TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) { + EXPECT_TRUE(matches("template struct A { A() { T i; } };" + "class Y { A a; }; Y y;", + declStmt(isInTemplateInstantiation()))); +} + +TEST(IsInTemplateInstantiation, NotMatchesDefinitionStmt) { + EXPECT_TRUE(notMatches("template struct A { void x() { T i; } };", + declStmt(isInTemplateInstantiation()))); +} + +TEST(IsInstantiated, MatchesFunctionInstantiation) { + EXPECT_TRUE( + matches("template void A(T t) { T i; } void x() { A(0); }", + functionDecl(isInstantiated()))); +} + +TEST(IsInstantiated, NotMatchesFunctionDefinition) { + EXPECT_TRUE(notMatches("template void A(T t) { T i; }", + varDecl(isInstantiated()))); +} + +TEST(IsInTemplateInstantiation, MatchesFunctionInstantiationStmt) { + EXPECT_TRUE( + matches("template void A(T t) { T i; } void x() { A(0); }", + declStmt(isInTemplateInstantiation()))); +} + +TEST(IsInTemplateInstantiation, NotMatchesFunctionDefinitionStmt) { + EXPECT_TRUE(notMatches("template 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 void A(T t) { j += 42; } void x() { A(0); }", + Matcher)); + EXPECT_TRUE(matches( + "int j; template void A(T t) { j += t; } void x() { A(0); }", + Matcher)); +} + TEST(IsExplicitTemplateSpecialization, DoesNotMatchPrimaryTemplate) { EXPECT_TRUE(notMatches(