brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.3 KiB · c0833dc Raw
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