1//===- unittests/AST/PostOrderASTVisitor.cpp - Declaration printer tests --===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains tests for the post-order traversing functionality
11// of RecursiveASTVisitor.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/RecursiveASTVisitor.h"
16#include "clang/Tooling/Tooling.h"
17#include "gtest/gtest.h"
18
19using namespace clang;
20
21namespace {
22
23  class RecordingVisitor
24    : public RecursiveASTVisitor<RecordingVisitor> {
25
26    bool VisitPostOrder;
27  public:
28    explicit RecordingVisitor(bool VisitPostOrder)
29      : VisitPostOrder(VisitPostOrder) {
30    }
31
32    // List of visited nodes during traversal.
33    std::vector<std::string> VisitedNodes;
34
35    bool shouldTraversePostOrder() const { return VisitPostOrder; }
36
37    bool VisitBinaryOperator(BinaryOperator *Op) {
38      VisitedNodes.push_back(Op->getOpcodeStr());
39      return true;
40    }
41
42    bool VisitIntegerLiteral(IntegerLiteral *Lit) {
43      VisitedNodes.push_back(Lit->getValue().toString(10, false));
44      return true;
45    }
46
47    bool VisitVarDecl(VarDecl* D) {
48      VisitedNodes.push_back(D->getNameAsString());
49      return true;
50    }
51
52    bool VisitCXXMethodDecl(CXXMethodDecl *D) {
53      VisitedNodes.push_back(D->getQualifiedNameAsString());
54      return true;
55    }
56
57    bool VisitReturnStmt(ReturnStmt *S) {
58      VisitedNodes.push_back("return");
59      return true;
60    }
61
62    bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
63      VisitedNodes.push_back(Declaration->getQualifiedNameAsString());
64      return true;
65    }
66
67    bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
68      VisitedNodes.push_back(T->getDecl()->getQualifiedNameAsString());
69      return true;
70    }
71  };
72
73}
74
75TEST(RecursiveASTVisitor, PostOrderTraversal) {
76  auto ASTUnit = tooling::buildASTFromCode(
77    "class A {"
78    "  class B {"
79    "    int foo() { while(4) { int i = 9; } return (1 + 3) + 2; }"
80    "  };"
81    "};"
82  );
83  auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
84  // We traverse the translation unit and store all
85  // visited nodes.
86  RecordingVisitor Visitor(true);
87  Visitor.TraverseTranslationUnitDecl(TU);
88
89  std::vector<std::string> expected = {
90    "4", "9", "i", "1", "3", "+", "2", "+", "return", "A::B::foo", "A::B", "A"
91  };
92  // Compare the list of actually visited nodes
93  // with the expected list of visited nodes.
94  ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size());
95  for (std::size_t I = 0; I < expected.size(); I++) {
96    ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]);
97  }
98}
99
100TEST(RecursiveASTVisitor, NoPostOrderTraversal) {
101  auto ASTUnit = tooling::buildASTFromCode(
102    "class A {"
103    "  class B {"
104    "    int foo() { return 1 + 2; }"
105    "  };"
106    "};"
107  );
108  auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
109  // We traverse the translation unit and store all
110  // visited nodes.
111  RecordingVisitor Visitor(false);
112  Visitor.TraverseTranslationUnitDecl(TU);
113
114  std::vector<std::string> expected = {
115    "A", "A::B", "A::B::foo", "return", "+", "1", "2"
116  };
117  // Compare the list of actually visited nodes
118  // with the expected list of visited nodes.
119  ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size());
120  for (std::size_t I = 0; I < expected.size(); I++) {
121    ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]);
122  }
123}
124