1 //===- unittests/Tooling/RecursiveASTVisitorPostOrderASTVisitor.cpp -------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains tests for the post-order traversing functionality 10 // of RecursiveASTVisitor. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "CRTPTestVisitor.h" 15 16 using namespace clang; 17 18 namespace { 19 class RecordingVisitor : public CRTPTestVisitor<RecordingVisitor> { 20 bool VisitPostOrder; 21 22 public: 23 explicit RecordingVisitor(bool VisitPostOrder) 24 : VisitPostOrder(VisitPostOrder) {} 25 26 // List of visited nodes during traversal. 27 std::vector<std::string> VisitedNodes; 28 29 bool shouldTraversePostOrder() const { return VisitPostOrder; } 30 31 bool VisitUnaryOperator(UnaryOperator *Op) { 32 VisitedNodes.push_back(std::string(Op->getOpcodeStr(Op->getOpcode()))); 33 return true; 34 } 35 36 bool VisitBinaryOperator(BinaryOperator *Op) { 37 VisitedNodes.push_back(std::string(Op->getOpcodeStr())); 38 return true; 39 } 40 41 bool VisitIntegerLiteral(IntegerLiteral *Lit) { 42 VisitedNodes.push_back(toString(Lit->getValue(), 10, false)); 43 return true; 44 } 45 46 bool VisitVarDecl(VarDecl *D) { 47 VisitedNodes.push_back(D->getNameAsString()); 48 return true; 49 } 50 51 bool VisitCXXMethodDecl(CXXMethodDecl *D) { 52 VisitedNodes.push_back(D->getQualifiedNameAsString()); 53 return true; 54 } 55 56 bool VisitReturnStmt(ReturnStmt *S) { 57 VisitedNodes.push_back("return"); 58 return true; 59 } 60 61 bool VisitCXXRecordDecl(CXXRecordDecl *D) { 62 if (!D->isImplicit()) 63 VisitedNodes.push_back(D->getQualifiedNameAsString()); 64 return true; 65 } 66 67 bool VisitTemplateTypeParmType(TemplateTypeParmType *T) { 68 VisitedNodes.push_back(T->getDecl()->getQualifiedNameAsString()); 69 return true; 70 } 71 }; 72 } // namespace 73 74 TEST(RecursiveASTVisitor, PostOrderTraversal) { 75 // We traverse the translation unit and store all visited nodes. 76 RecordingVisitor Visitor(true); 77 Visitor.runOver("class A {\n" 78 " class B {\n" 79 " int foo() {\n" 80 " while(4) { int i = 9; int j = -5; }\n" 81 " return (1 + 3) + 2; }\n" 82 " };\n" 83 "};\n"); 84 85 std::vector<std::string> expected = {"4", "9", "i", "5", "-", 86 "j", "1", "3", "+", "2", 87 "+", "return", "A::B::foo", "A::B", "A"}; 88 // Compare the list of actually visited nodes with the expected list of 89 // visited nodes. 90 ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size()); 91 for (std::size_t I = 0; I < expected.size(); I++) { 92 ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]); 93 } 94 } 95 96 TEST(RecursiveASTVisitor, NoPostOrderTraversal) { 97 // We traverse the translation unit and store all visited nodes. 98 RecordingVisitor Visitor(false); 99 Visitor.runOver("class A {\n" 100 " class B {\n" 101 " int foo() { return 1 + 2; }\n" 102 " };\n" 103 "};\n"); 104 105 std::vector<std::string> expected = {"A", "A::B", "A::B::foo", "return", 106 "+", "1", "2"}; 107 // Compare the list of actually visited nodes with the expected list of 108 // visited nodes. 109 ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size()); 110 for (std::size_t I = 0; I < expected.size(); I++) { 111 ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]); 112 } 113 } 114