228 lines · 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-exception6//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 LexicallyOrderedDeclVisitor20 : 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(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 {48 bool EmitDeclIndices, EmitStmtIndices;49 50public:51 DummyMatchVisitor(bool EmitDeclIndices = false, bool EmitStmtIndices = false)52 : EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}53 54 bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) override {55 const ASTContext &Context = TU->getASTContext();56 const SourceManager &SM = Context.getSourceManager();57 LexicallyOrderedDeclVisitor SubVisitor(*this, SM, EmitDeclIndices,58 EmitStmtIndices);59 SubVisitor.TraverseDecl(TU);60 return false;61 }62 63 template <class T> void match(StringRef Path, const T *D) {64 Match(Path, D->getBeginLoc());65 }66};67 68bool LexicallyOrderedDeclVisitor::TraverseStmt(Stmt *S) {69 Matcher.match("overridden TraverseStmt", S);70 return LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);71}72 73bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {74 std::string Path;75 llvm::raw_string_ostream OS(Path);76 assert(TraversalStack.back() == D);77 for (const Decl *D : TraversalStack) {78 if (isa<TranslationUnitDecl>(D)) {79 OS << "/";80 continue;81 }82 if (const auto *ND = dyn_cast<NamedDecl>(D))83 OS << ND->getNameAsString();84 else85 OS << "???";86 if (isa<DeclContext>(D) || isa<TemplateDecl>(D))87 OS << "/";88 }89 if (EmitDeclIndices)90 OS << "@" << Index++;91 Matcher.match(Path, D);92 return true;93}94 95bool LexicallyOrderedDeclVisitor::VisitDeclRefExpr(const DeclRefExpr *D) {96 std::string Name = D->getFoundDecl()->getNameAsString();97 llvm::raw_string_ostream OS(Name);98 if (EmitStmtIndices)99 OS << "@" << Index++;100 Matcher.match(Name, D);101 return true;102}103 104TEST(LexicallyOrderedRecursiveASTVisitor, VisitDeclsInImplementation) {105 StringRef Source = R"(106@interface I107@end108@implementation I109 110void nestedFunction() { }111 112- (void) method{ }113 114int anotherNestedFunction(int x) {115 return x;116}117 118int innerVariable = 0;119 120@end121 122int outerVariable = 0;123 124@implementation I(Cat)125 126void catF() { }127 128@end129 130void outerFunction() { }131)";132 DummyMatchVisitor Visitor;133 Visitor.DisallowMatch("/nestedFunction/", 6, 1);134 Visitor.ExpectMatch("/I/nestedFunction/", 6, 1);135 Visitor.ExpectMatch("/I/method/", 8, 1);136 Visitor.DisallowMatch("/anotherNestedFunction/", 10, 1);137 Visitor.ExpectMatch("/I/anotherNestedFunction/", 10, 1);138 Visitor.DisallowMatch("/innerVariable", 14, 1);139 Visitor.ExpectMatch("/I/innerVariable", 14, 1);140 Visitor.ExpectMatch("/outerVariable", 18, 1);141 Visitor.DisallowMatch("/catF/", 22, 1);142 Visitor.ExpectMatch("/Cat/catF/", 22, 1);143 Visitor.ExpectMatch("/outerFunction/", 26, 1);144 EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));145}146 147TEST(LexicallyOrderedRecursiveASTVisitor, VisitMacroDeclsInImplementation) {148 StringRef Source = R"(149@interface I150@end151 152void outerFunction() { }153 154#define MACRO_F(x) void nestedFunction##x() { }155 156@implementation I157 158MACRO_F(1)159 160@end161 162MACRO_F(2)163)";164 DummyMatchVisitor Visitor;165 Visitor.ExpectMatch("/outerFunction/", 5, 1);166 Visitor.ExpectMatch("/I/nestedFunction1/", 7, 20);167 Visitor.ExpectMatch("/nestedFunction2/", 7, 20);168 EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));169}170 171TEST(LexicallyOrderedRecursiveASTVisitor, VisitTemplateDecl) {172 StringRef Source = R"(173template <class T> T f();174template <class U, class = void> class Class {};175)";176 DummyMatchVisitor Visitor(/*EmitIndices=*/true);177 Visitor.ExpectMatch("/f/T@1", 2, 11);178 Visitor.ExpectMatch("/f/f/@2", 2, 20);179 Visitor.ExpectMatch("/Class/U@4", 3, 11);180 Visitor.ExpectMatch("/Class/@5", 3, 20);181 Visitor.ExpectMatch("/Class/Class/@6", 3, 34);182 EXPECT_TRUE(Visitor.runOver(Source));183}184 185TEST(LexicallyOrderedRecursiveASTVisitor, VisitCXXOperatorCallExpr) {186 StringRef Source = R"(187struct S {188 S &operator+(S&);189 S *operator->();190 S &operator++();191 S operator++(int);192 void operator()(int, int);193 void operator[](int);194 void f();195};196S a, b, c;197 198void test() {199 a = b + c;200 a->f();201 a(1, 2);202 b[0];203 ++a;204 b++;205}206)";207 DummyMatchVisitor Visitor(/*EmitDeclIndices=*/false,208 /*EmitStmtIndices=*/true);209 // There are two overloaded operators that start at this point210 // This makes sure they are both traversed using the overridden211 // TraverseStmt, as the traversal is implemented by us for212 // CXXOperatorCallExpr.213 Visitor.ExpectMatch("overridden TraverseStmt", 14, 3, 2);214 Visitor.ExpectMatch("a@0", 14, 3);215 Visitor.ExpectMatch("operator=@1", 14, 5);216 Visitor.ExpectMatch("b@2", 14, 7);217 Visitor.ExpectMatch("operator+@3", 14, 9);218 Visitor.ExpectMatch("c@4", 14, 11);219 Visitor.ExpectMatch("operator->@6", 15, 4);220 Visitor.ExpectMatch("operator()@8", 16, 4);221 Visitor.ExpectMatch("operator[]@10", 17, 4);222 Visitor.ExpectMatch("operator++@11", 18, 3);223 Visitor.ExpectMatch("operator++@14", 19, 4);224 EXPECT_TRUE(Visitor.runOver(Source));225}226 227} // end anonymous namespace228