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