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