Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1802,11 +1802,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,47 @@ } }; -} + // 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 visitPostOrder; + public: + + ASTSerializerVisitor(bool visitPostOrder, std::vector& visitedNodes) + : visitedNodes (visitedNodes) + , visitPostOrder (visitPostOrder) + {} + + bool shouldTraversePostOrder() const + { + return visitPostOrder; + } + + bool VisitStmt(Stmt *s) + { + visitedNodes.push_back(s); + return true; + } + + bool PostVisitStmt(Stmt *s) + { + if (visitPostOrder) + 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 +167,32 @@ 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()); +}