Clang Project

clang_source_code/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
1//===- unittest/Tooling/LexicallyOrderedRecursiveASTVisitorTest.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#include "TestVisitor.h"
10#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
11#include <stack>
12
13using namespace clang;
14
15namespace {
16
17class DummyMatchVisitor;
18
19class LexicallyOrderedDeclVisitor
20    : public LexicallyOrderedRecursiveASTVisitor<LexicallyOrderedDeclVisitor> {
21public:
22  LexicallyOrderedDeclVisitor(DummyMatchVisitor &Matcher,
23                              const SourceManager &SMbool EmitDeclIndices,
24                              bool EmitStmtIndices)
25      : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher),
26        EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
27
28  bool TraverseDecl(Decl *D) {
29    TraversalStack.push_back(D);
30    LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
31    TraversalStack.pop_back();
32    return true;
33  }
34
35  bool TraverseStmt(Stmt *S);
36
37  bool VisitNamedDecl(const NamedDecl *D);
38  bool VisitDeclRefExpr(const DeclRefExpr *D);
39
40private:
41  DummyMatchVisitor &Matcher;
42  bool EmitDeclIndicesEmitStmtIndices;
43  unsigned Index = 0;
44  llvm::SmallVector<Decl *, 8TraversalStack;
45};
46
47class DummyMatchVisitor : public ExpectedLocationVisitor<DummyMatchVisitor> {
48  bool EmitDeclIndicesEmitStmtIndices;
49
50public:
51  DummyMatchVisitor(bool EmitDeclIndices = falsebool EmitStmtIndices = false)
52      : EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
53  bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
54    const ASTContext &Context = TU->getASTContext();
55    const SourceManager &SM = Context.getSourceManager();
56    LexicallyOrderedDeclVisitor SubVisitor(*thisSMEmitDeclIndices,
57                                           EmitStmtIndices);
58    SubVisitor.TraverseDecl(TU);
59    return false;
60  }
61
62  template <class T> void match(StringRef Pathconst T *D) {
63    Match(Path, D->getBeginLoc());
64  }
65};
66
67bool LexicallyOrderedDeclVisitor::TraverseStmt(Stmt *S) {
68  Matcher.match("overridden TraverseStmt"S);
69  return LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);
70}
71
72bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
73  std::string Path;
74  llvm::raw_string_ostream OS(Path);
75  assert(TraversalStack.back() == D);
76  for (const Decl *D : TraversalStack) {
77    if (isa<TranslationUnitDecl>(D)) {
78      OS << "/";
79      continue;
80    }
81    if (const auto *ND = dyn_cast<NamedDecl>(D))
82      OS << ND->getNameAsString();
83    else
84      OS << "???";
85    if (isa<DeclContext>(D) || isa<TemplateDecl>(D))
86      OS << "/";
87  }
88  if (EmitDeclIndices)
89    OS << "@" << Index++;
90  Matcher.match(OS.str(), D);
91  return true;
92}
93
94bool LexicallyOrderedDeclVisitor::VisitDeclRefExpr(const DeclRefExpr *D) {
95  std::string Name = D->getFoundDecl()->getNameAsString();
96  llvm::raw_string_ostream OS(Name);
97  if (EmitStmtIndices)
98    OS << "@" << Index++;
99  Matcher.match(OS.str(), D);
100  return true;
101}
102
103TEST(LexicallyOrderedRecursiveASTVisitor, VisitDeclsInImplementation) {
104  StringRef Source = R"(
105@interface I
106@end
107@implementation I
108
109int nestedFunction() { }
110
111- (void) method{ }
112
113int anotherNestedFunction(int x) {
114  return x;
115}
116
117int innerVariable = 0;
118
119@end
120
121int outerVariable = 0;
122
123@implementation I(Cat)
124
125void catF() { }
126
127@end
128
129void outerFunction() { }
130)";
131  DummyMatchVisitor Visitor;
132  Visitor.DisallowMatch("/nestedFunction/"61);
133  Visitor.ExpectMatch("/I/nestedFunction/"61);
134  Visitor.ExpectMatch("/I/method/"81);
135  Visitor.DisallowMatch("/anotherNestedFunction/"101);
136  Visitor.ExpectMatch("/I/anotherNestedFunction/"101);
137  Visitor.DisallowMatch("/innerVariable"141);
138  Visitor.ExpectMatch("/I/innerVariable"141);
139  Visitor.ExpectMatch("/outerVariable"181);
140  Visitor.DisallowMatch("/catF/"221);
141  Visitor.ExpectMatch("/Cat/catF/"221);
142  Visitor.ExpectMatch("/outerFunction/"261);
143  EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
144}
145
146TEST(LexicallyOrderedRecursiveASTVisitor, VisitMacroDeclsInImplementation) {
147  StringRef Source = R"(
148@interface I
149@end
150
151void outerFunction() { }
152
153#define MACRO_F(x) void nestedFunction##x() { }
154
155@implementation I
156
157MACRO_F(1)
158
159@end
160
161MACRO_F(2)
162)";
163  DummyMatchVisitor Visitor;
164  Visitor.ExpectMatch("/outerFunction/"51);
165  Visitor.ExpectMatch("/I/nestedFunction1/"720);
166  Visitor.ExpectMatch("/nestedFunction2/"720);
167  EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
168}
169
170TEST(LexicallyOrderedRecursiveASTVisitor, VisitTemplateDecl) {
171  StringRef Source = R"(
172template <class T> T f();
173template <class U, class = void> class Class {};
174)";
175  DummyMatchVisitor Visitor(/*EmitIndices=*/true);
176  Visitor.ExpectMatch("/f/T@1"211);
177  Visitor.ExpectMatch("/f/f/@2"220);
178  Visitor.ExpectMatch("/Class/U@4"311);
179  Visitor.ExpectMatch("/Class/@5"320);
180  Visitor.ExpectMatch("/Class/Class/@6"334);
181  EXPECT_TRUE(Visitor.runOver(Source));
182}
183
184TEST(LexicallyOrderedRecursiveASTVisitor, VisitCXXOperatorCallExpr) {
185  StringRef Source = R"(
186struct S {
187  S &operator+(S&);
188  S *operator->();
189  S &operator++();
190  S operator++(int);
191  void operator()(int, int);
192  void operator[](int);
193  void f();
194};
195S a, b, c;
196
197void test() {
198  a = b + c;
199  a->f();
200  a(1, 2);
201  b[0];
202  ++a;
203  b++;
204}
205)";
206  DummyMatchVisitor Visitor(/*EmitDeclIndices=*/false,
207                            /*EmitStmtIndices=*/true);
208  // There are two overloaded operators that start at this point
209  // This makes sure they are both traversed using the overridden
210  // TraverseStmt, as the traversal is implemented by us for
211  // CXXOperatorCallExpr.
212  Visitor.ExpectMatch("overridden TraverseStmt"1432);
213  Visitor.ExpectMatch("a@0"143);
214  Visitor.ExpectMatch("operator=@1"145);
215  Visitor.ExpectMatch("b@2"147);
216  Visitor.ExpectMatch("operator+@3"149);
217  Visitor.ExpectMatch("c@4"1411);
218  Visitor.ExpectMatch("operator->@6"154);
219  Visitor.ExpectMatch("operator()@8"164);
220  Visitor.ExpectMatch("operator[]@10"174);
221  Visitor.ExpectMatch("operator++@11"183);
222  Visitor.ExpectMatch("operator++@14"194);
223  EXPECT_TRUE(Visitor.runOver(Source));
224}
225
226// end anonymous namespace
227