diff options
| author | Nico Weber <nicolasweber@gmx.de> | 2016-09-13 15:05:04 +0000 |
|---|---|---|
| committer | Nico Weber <nicolasweber@gmx.de> | 2016-09-13 15:05:04 +0000 |
| commit | 6339f1a028c7e9cc5150fcdd6b5363ee952e931f (patch) | |
| tree | 0b4b424829f1984dc2b831e33a1ae60b5b166093 | |
| parent | 2574d15c5be1ef54041e0558e0bf2f381ae07f02 (diff) | |
| download | bcm5719-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.h | 20 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp | 83 |
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( |

