Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1835,11 +1835,10 @@ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); \ if (!getDerived().shouldVisitTemplateInstantiations() && \ D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \ - /* Returning from here skips traversing the \ - declaration context of the *TemplateSpecializationDecl \ - (embedded in the DEF_TRAVERSE_DECL() macro) \ - which contains the instantiated members of the template. */ \ - return true; \ + /* Skip traversing the declaration context of the \ + *TemplateSpecializationDecl (embedded in the DEF_TRAVERSE_DECL() \ + macro) which contains the instantiated members of the template. */ \ + ShouldVisitChildren = false; \ }) DEF_TRAVERSE_TMPL_SPEC_DECL(Class) Index: unittests/AST/PostOrderASTVisitor.cpp =================================================================== --- unittests/AST/PostOrderASTVisitor.cpp +++ unittests/AST/PostOrderASTVisitor.cpp @@ -15,6 +15,7 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Tooling/Tooling.h" #include "gtest/gtest.h" +#include using namespace clang; @@ -75,7 +76,33 @@ } }; -} + +// Serializes the AST. It is not complete! It only serializes the Statement +// and the Declaration nodes. +class ASTSerializerVisitor : public RecursiveASTVisitor { +private: + std::vector &VisitedNodes; + const bool PostOrderTraverse; + +public: + ASTSerializerVisitor(bool PostOrderTraverse, + std::vector &VisitedNodes) + : VisitedNodes(VisitedNodes), PostOrderTraverse(PostOrderTraverse) {} + + bool shouldTraversePostOrder() const { return PostOrderTraverse; } + + bool VisitStmt(Stmt *S) { + VisitedNodes.push_back(S); + return true; + } + + bool VisitDecl(Decl *D) { + VisitedNodes.push_back(D); + return true; + } +}; + +} // anonymous namespace TEST(RecursiveASTVisitor, PostOrderTraversal) { auto ASTUnit = tooling::buildASTFromCode( @@ -126,3 +153,30 @@ ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]); } } + +TEST(RecursiveASTVisitor, PrePostComparisonTest) { + auto ASTUnit = tooling::buildASTFromCode("template class X {};" + "template class X;"); + + auto TU = ASTUnit->getASTContext().getTranslationUnitDecl(); + + std::vector PreorderNodeList, PostorderNodeList; + + ASTSerializerVisitor PreVisitor(false, PreorderNodeList); + PreVisitor.TraverseTranslationUnitDecl(TU); + + ASTSerializerVisitor PostVisitor(true, PostorderNodeList); + PostVisitor.TraverseTranslationUnitDecl(TU); + + // The number of visited nodes must be independent of the ordering mode. + ASSERT_EQ(PreorderNodeList.size(), PostorderNodeList.size()); + + std::sort(PreorderNodeList.begin(), PreorderNodeList.end()); + std::sort(PostorderNodeList.begin(), PostorderNodeList.end()); + + // Both traversal must visit the same nodes. + ASSERT_EQ(std::mismatch(PreorderNodeList.begin(), PreorderNodeList.end(), + PostorderNodeList.begin()) + .first, + PreorderNodeList.end()); +}