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 
13 using namespace clang;
14 
15 namespace {
16 
17 class DummyMatchVisitor;
18 
19 class LexicallyOrderedDeclVisitor
20     : public LexicallyOrderedRecursiveASTVisitor<LexicallyOrderedDeclVisitor> {
21 public:
LexicallyOrderedDeclVisitor(DummyMatchVisitor & Matcher,const SourceManager & SM,bool EmitDeclIndices,bool EmitStmtIndices)22   LexicallyOrderedDeclVisitor(DummyMatchVisitor &Matcher,
23                               const SourceManager &SM, bool EmitDeclIndices,
24                               bool EmitStmtIndices)
25       : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher),
26         EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
27 
TraverseDecl(Decl * D)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 
40 private:
41   DummyMatchVisitor &Matcher;
42   bool EmitDeclIndices, EmitStmtIndices;
43   unsigned Index = 0;
44   llvm::SmallVector<Decl *, 8> TraversalStack;
45 };
46 
47 class DummyMatchVisitor : public ExpectedLocationVisitor<DummyMatchVisitor> {
48   bool EmitDeclIndices, EmitStmtIndices;
49 
50 public:
DummyMatchVisitor(bool EmitDeclIndices=false,bool EmitStmtIndices=false)51   DummyMatchVisitor(bool EmitDeclIndices = false, bool EmitStmtIndices = false)
52       : EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
VisitTranslationUnitDecl(TranslationUnitDecl * TU)53   bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
54     const ASTContext &Context = TU->getASTContext();
55     const SourceManager &SM = Context.getSourceManager();
56     LexicallyOrderedDeclVisitor SubVisitor(*this, SM, EmitDeclIndices,
57                                            EmitStmtIndices);
58     SubVisitor.TraverseDecl(TU);
59     return false;
60   }
61 
match(StringRef Path,const T * D)62   template <class T> void match(StringRef Path, const T *D) {
63     Match(Path, D->getBeginLoc());
64   }
65 };
66 
TraverseStmt(Stmt * S)67 bool LexicallyOrderedDeclVisitor::TraverseStmt(Stmt *S) {
68   Matcher.match("overridden TraverseStmt", S);
69   return LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);
70 }
71 
VisitNamedDecl(const NamedDecl * D)72 bool 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 
VisitDeclRefExpr(const DeclRefExpr * D)94 bool 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 
TEST(LexicallyOrderedRecursiveASTVisitor,VisitDeclsInImplementation)103 TEST(LexicallyOrderedRecursiveASTVisitor, VisitDeclsInImplementation) {
104   StringRef Source = R"(
105 @interface I
106 @end
107 @implementation I
108 
109 int nestedFunction() { }
110 
111 - (void) method{ }
112 
113 int anotherNestedFunction(int x) {
114   return x;
115 }
116 
117 int innerVariable = 0;
118 
119 @end
120 
121 int outerVariable = 0;
122 
123 @implementation I(Cat)
124 
125 void catF() { }
126 
127 @end
128 
129 void outerFunction() { }
130 )";
131   DummyMatchVisitor Visitor;
132   Visitor.DisallowMatch("/nestedFunction/", 6, 1);
133   Visitor.ExpectMatch("/I/nestedFunction/", 6, 1);
134   Visitor.ExpectMatch("/I/method/", 8, 1);
135   Visitor.DisallowMatch("/anotherNestedFunction/", 10, 1);
136   Visitor.ExpectMatch("/I/anotherNestedFunction/", 10, 1);
137   Visitor.DisallowMatch("/innerVariable", 14, 1);
138   Visitor.ExpectMatch("/I/innerVariable", 14, 1);
139   Visitor.ExpectMatch("/outerVariable", 18, 1);
140   Visitor.DisallowMatch("/catF/", 22, 1);
141   Visitor.ExpectMatch("/Cat/catF/", 22, 1);
142   Visitor.ExpectMatch("/outerFunction/", 26, 1);
143   EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
144 }
145 
TEST(LexicallyOrderedRecursiveASTVisitor,VisitMacroDeclsInImplementation)146 TEST(LexicallyOrderedRecursiveASTVisitor, VisitMacroDeclsInImplementation) {
147   StringRef Source = R"(
148 @interface I
149 @end
150 
151 void outerFunction() { }
152 
153 #define MACRO_F(x) void nestedFunction##x() { }
154 
155 @implementation I
156 
157 MACRO_F(1)
158 
159 @end
160 
161 MACRO_F(2)
162 )";
163   DummyMatchVisitor Visitor;
164   Visitor.ExpectMatch("/outerFunction/", 5, 1);
165   Visitor.ExpectMatch("/I/nestedFunction1/", 7, 20);
166   Visitor.ExpectMatch("/nestedFunction2/", 7, 20);
167   EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
168 }
169 
TEST(LexicallyOrderedRecursiveASTVisitor,VisitTemplateDecl)170 TEST(LexicallyOrderedRecursiveASTVisitor, VisitTemplateDecl) {
171   StringRef Source = R"(
172 template <class T> T f();
173 template <class U, class = void> class Class {};
174 )";
175   DummyMatchVisitor Visitor(/*EmitIndices=*/true);
176   Visitor.ExpectMatch("/f/T@1", 2, 11);
177   Visitor.ExpectMatch("/f/f/@2", 2, 20);
178   Visitor.ExpectMatch("/Class/U@4", 3, 11);
179   Visitor.ExpectMatch("/Class/@5", 3, 20);
180   Visitor.ExpectMatch("/Class/Class/@6", 3, 34);
181   EXPECT_TRUE(Visitor.runOver(Source));
182 }
183 
TEST(LexicallyOrderedRecursiveASTVisitor,VisitCXXOperatorCallExpr)184 TEST(LexicallyOrderedRecursiveASTVisitor, VisitCXXOperatorCallExpr) {
185   StringRef Source = R"(
186 struct 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 };
195 S a, b, c;
196 
197 void 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", 14, 3, 2);
213   Visitor.ExpectMatch("a@0", 14, 3);
214   Visitor.ExpectMatch("operator=@1", 14, 5);
215   Visitor.ExpectMatch("b@2", 14, 7);
216   Visitor.ExpectMatch("operator+@3", 14, 9);
217   Visitor.ExpectMatch("c@4", 14, 11);
218   Visitor.ExpectMatch("operator->@6", 15, 4);
219   Visitor.ExpectMatch("operator()@8", 16, 4);
220   Visitor.ExpectMatch("operator[]@10", 17, 4);
221   Visitor.ExpectMatch("operator++@11", 18, 3);
222   Visitor.ExpectMatch("operator++@14", 19, 4);
223   EXPECT_TRUE(Visitor.runOver(Source));
224 }
225 
226 } // end anonymous namespace
227