summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2016-09-13 15:05:04 +0000
committerNico Weber <nicolasweber@gmx.de>2016-09-13 15:05:04 +0000
commit6339f1a028c7e9cc5150fcdd6b5363ee952e931f (patch)
tree0b4b424829f1984dc2b831e33a1ae60b5b166093
parent2574d15c5be1ef54041e0558e0bf2f381ae07f02 (diff)
downloadbcm5719-llvm-6339f1a028c7e9cc5150fcdd6b5363ee952e931f.tar.gz
bcm5719-llvm-6339f1a028c7e9cc5150fcdd6b5363ee952e931f.zip
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
-rw-r--r--clang/include/clang/AST/RecursiveASTVisitor.h20
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp83
2 files changed, 103 insertions, 0 deletions
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 0f010338faf..77decd798ff 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -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)
@@ -1534,6 +1539,16 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
}
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) {
for (auto *SD : D->specializations()) {
@@ -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()));
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index fcd3dcb5af0..ff45fe6c510 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -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(
OpenPOWER on IntegriCloud