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 &SM, bool EmitDeclIndices,
24 bool EmitStmtIndices)
25 : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher),
26 EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
27
28 bool TraverseDecl(Decl *D) {
29 TraversalStack.push_back(Elt: 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 EmitDeclIndices, EmitStmtIndices;
43 unsigned Index = 0;
44 llvm::SmallVector<Decl *, 8> TraversalStack;
45};
46
47class DummyMatchVisitor : public ExpectedLocationVisitor<DummyMatchVisitor> {
48 bool EmitDeclIndices, EmitStmtIndices;
49
50public:
51 DummyMatchVisitor(bool EmitDeclIndices = false, bool 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(*this, SM, EmitDeclIndices,
57 EmitStmtIndices);
58 SubVisitor.TraverseDecl(TU);
59 return false;
60 }
61
62 template <class T> void match(StringRef Path, const T *D) {
63 Match(Name: Path, Location: D->getBeginLoc());
64 }
65};
66
67bool LexicallyOrderedDeclVisitor::TraverseStmt(Stmt *S) {
68 Matcher.match(Path: "overridden TraverseStmt", D: 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>(Val: D)) {
78 OS << "/";
79 continue;
80 }
81 if (const auto *ND = dyn_cast<NamedDecl>(Val: D))
82 OS << ND->getNameAsString();
83 else
84 OS << "???";
85 if (isa<DeclContext>(Val: D) || isa<TemplateDecl>(Val: D))
86 OS << "/";
87 }
88 if (EmitDeclIndices)
89 OS << "@" << Index++;
90 Matcher.match(Path: 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(Path: 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(Match: "/nestedFunction/", Line: 6, Column: 1);
133 Visitor.ExpectMatch(Match: "/I/nestedFunction/", Line: 6, Column: 1);
134 Visitor.ExpectMatch(Match: "/I/method/", Line: 8, Column: 1);
135 Visitor.DisallowMatch(Match: "/anotherNestedFunction/", Line: 10, Column: 1);
136 Visitor.ExpectMatch(Match: "/I/anotherNestedFunction/", Line: 10, Column: 1);
137 Visitor.DisallowMatch(Match: "/innerVariable", Line: 14, Column: 1);
138 Visitor.ExpectMatch(Match: "/I/innerVariable", Line: 14, Column: 1);
139 Visitor.ExpectMatch(Match: "/outerVariable", Line: 18, Column: 1);
140 Visitor.DisallowMatch(Match: "/catF/", Line: 22, Column: 1);
141 Visitor.ExpectMatch(Match: "/Cat/catF/", Line: 22, Column: 1);
142 Visitor.ExpectMatch(Match: "/outerFunction/", Line: 26, Column: 1);
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(Match: "/outerFunction/", Line: 5, Column: 1);
165 Visitor.ExpectMatch(Match: "/I/nestedFunction1/", Line: 7, Column: 20);
166 Visitor.ExpectMatch(Match: "/nestedFunction2/", Line: 7, Column: 20);
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(Match: "/f/T@1", Line: 2, Column: 11);
177 Visitor.ExpectMatch(Match: "/f/f/@2", Line: 2, Column: 20);
178 Visitor.ExpectMatch(Match: "/Class/U@4", Line: 3, Column: 11);
179 Visitor.ExpectMatch(Match: "/Class/@5", Line: 3, Column: 20);
180 Visitor.ExpectMatch(Match: "/Class/Class/@6", Line: 3, Column: 34);
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(Match: "overridden TraverseStmt", Line: 14, Column: 3, Times: 2);
213 Visitor.ExpectMatch(Match: "a@0", Line: 14, Column: 3);
214 Visitor.ExpectMatch(Match: "operator=@1", Line: 14, Column: 5);
215 Visitor.ExpectMatch(Match: "b@2", Line: 14, Column: 7);
216 Visitor.ExpectMatch(Match: "operator+@3", Line: 14, Column: 9);
217 Visitor.ExpectMatch(Match: "c@4", Line: 14, Column: 11);
218 Visitor.ExpectMatch(Match: "operator->@6", Line: 15, Column: 4);
219 Visitor.ExpectMatch(Match: "operator()@8", Line: 16, Column: 4);
220 Visitor.ExpectMatch(Match: "operator[]@10", Line: 17, Column: 4);
221 Visitor.ExpectMatch(Match: "operator++@11", Line: 18, Column: 3);
222 Visitor.ExpectMatch(Match: "operator++@14", Line: 19, Column: 4);
223 EXPECT_TRUE(Visitor.runOver(Source));
224}
225
226} // end anonymous namespace
227

source code of clang/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp