Traversing template paramter lists of DeclaratorDecls and/or TagDecls.

The unit tests in this patch demonstrate the need to traverse template
parameter lists of DeclaratorDecls (e.g. VarDecls, CXXMethodDecls) and
TagDecls (e.g. EnumDecls, RecordDecls).

Fixes PR29042.
https://reviews.llvm.org/D24268

Patch from Lukasz
Łukasz Anforowicz <lukasza@chromium.org>!

llvm-svn: 281345
This commit is contained in:
Nico Weber 2016-09-13 15:05:04 +00:00
parent 2574d15c5b
commit 6339f1a028
2 changed files with 103 additions and 0 deletions

View File

@ -482,6 +482,11 @@ public:
private:
// These are helper methods used by more than one Traverse* method.
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
// Traverses template parameter lists of either a DeclaratorDecl or TagDecl.
template <typename T>
bool TraverseDeclTemplateParameterLists(T *D);
#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D);
DEF_TRAVERSE_TMPL_INST(Class)
@ -1533,6 +1538,16 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
return true;
}
template <typename Derived>
template <typename T>
bool RecursiveASTVisitor<Derived>::TraverseDeclTemplateParameterLists(T *D) {
for (unsigned i = 0; i < D->getNumTemplateParameterLists(); i++) {
TemplateParameterList *TPL = D->getTemplateParameterList(i);
TraverseTemplateParameterListHelper(TPL);
}
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
ClassTemplateDecl *D) {
@ -1694,6 +1709,8 @@ DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
})
DEF_TRAVERSE_DECL(EnumDecl, {
TRY_TO(TraverseDeclTemplateParameterLists(D));
if (D->getTypeForDecl())
TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
@ -1708,6 +1725,7 @@ bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(RecordDecl *D) {
// We shouldn't traverse D->getTypeForDecl(); it's a result of
// declaring the type, not something that was written in the source.
TRY_TO(TraverseDeclTemplateParameterLists(D));
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
return true;
}
@ -1802,6 +1820,7 @@ DEF_TRAVERSE_DECL(IndirectFieldDecl, {})
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) {
TRY_TO(TraverseDeclTemplateParameterLists(D));
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
if (D->getTypeSourceInfo())
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
@ -1848,6 +1867,7 @@ DEF_TRAVERSE_DECL(ObjCIvarDecl, {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
TRY_TO(TraverseDeclTemplateParameterLists(D));
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));

View File

@ -641,6 +641,89 @@ TEST(TemplateArgument, Matches) {
functionDecl(hasAnyTemplateArgument(templateArgument()))));
}
TEST(TemplateTypeParmDecl, CXXMethodDecl) {
const char input[] =
"template<typename T>\n"
"class Class {\n"
" void method();\n"
"};\n"
"template<typename U>\n"
"void Class<U>::method() {}\n";
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
}
TEST(TemplateTypeParmDecl, VarDecl) {
const char input[] =
"template<typename T>\n"
"class Class {\n"
" static T pi;\n"
"};\n"
"template<typename U>\n"
"U Class<U>::pi = U(3.1415926535897932385);\n";
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
}
TEST(TemplateTypeParmDecl, VarTemplatePartialSpecializationDecl) {
const char input[] =
"template<typename T>\n"
"struct Struct {\n"
" template<typename T2> static int field;\n"
"};\n"
"template<typename U>\n"
"template<typename U2>\n"
"int Struct<U>::field<char> = 123;\n";
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U2"))));
}
TEST(TemplateTypeParmDecl, ClassTemplatePartialSpecializationDecl) {
const char input[] =
"template<typename T>\n"
"class Class {\n"
" template<typename T2> struct Struct;\n"
"};\n"
"template<typename U>\n"
"template<typename U2>\n"
"struct Class<U>::Struct<int> {};\n";
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U2"))));
}
TEST(TemplateTypeParmDecl, EnumDecl) {
const char input[] =
"template<typename T>\n"
"struct Struct {\n"
" enum class Enum : T;\n"
"};\n"
"template<typename U>\n"
"enum class Struct<U>::Enum : U {\n"
" e1,\n"
" e2\n"
"};\n";
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
}
TEST(TemplateTypeParmDecl, RecordDecl) {
const char input[] =
"template<typename T>\n"
"class Class {\n"
" struct Struct;\n"
"};\n"
"template<typename U>\n"
"struct Class<U>::Struct {\n"
" U field;\n"
"};\n";
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
}
TEST(RefersToIntegralType, Matches) {
EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;",
classTemplateSpecializationDecl(