brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · c5ad29a Raw
199 lines · cpp
1//===- unittest/AST/RecursiveASTVisitorTest.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 "clang/AST/RecursiveASTVisitor.h"10#include "clang/AST/ASTConsumer.h"11#include "clang/AST/ASTContext.h"12#include "clang/AST/Attr.h"13#include "clang/AST/Decl.h"14#include "clang/AST/TypeLoc.h"15#include "clang/Frontend/FrontendAction.h"16#include "clang/Tooling/Tooling.h"17#include "llvm/ADT/FunctionExtras.h"18#include "llvm/ADT/STLExtras.h"19#include "gmock/gmock.h"20#include "gtest/gtest.h"21#include <cassert>22 23using namespace clang;24using ::testing::ElementsAre;25 26namespace {27class ProcessASTAction : public clang::ASTFrontendAction {28public:29  ProcessASTAction(llvm::unique_function<void(clang::ASTContext &)> Process)30      : Process(std::move(Process)) {31    assert(this->Process);32  }33 34  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,35                                                 StringRef InFile) {36    class Consumer : public ASTConsumer {37    public:38      Consumer(llvm::function_ref<void(ASTContext &CTx)> Process)39          : Process(Process) {}40 41      void HandleTranslationUnit(ASTContext &Ctx) override { Process(Ctx); }42 43    private:44      llvm::function_ref<void(ASTContext &CTx)> Process;45    };46 47    return std::make_unique<Consumer>(Process);48  }49 50private:51  llvm::unique_function<void(clang::ASTContext &)> Process;52};53 54enum class VisitEvent {55  StartTraverseFunction,56  EndTraverseFunction,57  StartTraverseAttr,58  EndTraverseAttr,59  StartTraverseEnum,60  EndTraverseEnum,61  StartTraverseTypedefType,62  EndTraverseTypedefType,63  StartTraverseObjCInterface,64  EndTraverseObjCInterface,65  StartTraverseObjCProtocol,66  EndTraverseObjCProtocol,67  StartTraverseObjCProtocolLoc,68  EndTraverseObjCProtocolLoc,69};70 71class CollectInterestingEvents72    : public RecursiveASTVisitor<CollectInterestingEvents> {73public:74  bool TraverseFunctionDecl(FunctionDecl *D) {75    Events.push_back(VisitEvent::StartTraverseFunction);76    bool Ret = RecursiveASTVisitor::TraverseFunctionDecl(D);77    Events.push_back(VisitEvent::EndTraverseFunction);78 79    return Ret;80  }81 82  bool TraverseAttr(Attr *A) {83    Events.push_back(VisitEvent::StartTraverseAttr);84    bool Ret = RecursiveASTVisitor::TraverseAttr(A);85    Events.push_back(VisitEvent::EndTraverseAttr);86 87    return Ret;88  }89 90  bool TraverseEnumDecl(EnumDecl *D) {91    Events.push_back(VisitEvent::StartTraverseEnum);92    bool Ret = RecursiveASTVisitor::TraverseEnumDecl(D);93    Events.push_back(VisitEvent::EndTraverseEnum);94 95    return Ret;96  }97 98  bool TraverseTypedefTypeLoc(TypedefTypeLoc TL, bool TraverseQualifier) {99    Events.push_back(VisitEvent::StartTraverseTypedefType);100    bool Ret =101        RecursiveASTVisitor::TraverseTypedefTypeLoc(TL, TraverseQualifier);102    Events.push_back(VisitEvent::EndTraverseTypedefType);103 104    return Ret;105  }106 107  bool TraverseObjCInterfaceDecl(ObjCInterfaceDecl *ID) {108    Events.push_back(VisitEvent::StartTraverseObjCInterface);109    bool Ret = RecursiveASTVisitor::TraverseObjCInterfaceDecl(ID);110    Events.push_back(VisitEvent::EndTraverseObjCInterface);111 112    return Ret;113  }114 115  bool TraverseObjCProtocolDecl(ObjCProtocolDecl *PD) {116    Events.push_back(VisitEvent::StartTraverseObjCProtocol);117    bool Ret = RecursiveASTVisitor::TraverseObjCProtocolDecl(PD);118    Events.push_back(VisitEvent::EndTraverseObjCProtocol);119 120    return Ret;121  }122 123  bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) {124    Events.push_back(VisitEvent::StartTraverseObjCProtocolLoc);125    bool Ret = RecursiveASTVisitor::TraverseObjCProtocolLoc(ProtocolLoc);126    Events.push_back(VisitEvent::EndTraverseObjCProtocolLoc);127 128    return Ret;129  }130 131  std::vector<VisitEvent> takeEvents() && { return std::move(Events); }132 133private:134  std::vector<VisitEvent> Events;135};136 137std::vector<VisitEvent> collectEvents(llvm::StringRef Code,138                                      const Twine &FileName = "input.cc") {139  CollectInterestingEvents Visitor;140  clang::tooling::runToolOnCode(141      std::make_unique<ProcessASTAction>(142          [&](clang::ASTContext &Ctx) { Visitor.TraverseAST(Ctx); }),143      Code, FileName);144  return std::move(Visitor).takeEvents();145}146} // namespace147 148TEST(RecursiveASTVisitorTest, AttributesInsideDecls) {149  /// Check attributes are traversed inside TraverseFunctionDecl.150  llvm::StringRef Code = R"cpp(151__attribute__((annotate("something"))) int foo() { return 10; }152  )cpp";153 154  EXPECT_THAT(collectEvents(Code),155              ElementsAre(VisitEvent::StartTraverseFunction,156                          VisitEvent::StartTraverseAttr,157                          VisitEvent::EndTraverseAttr,158                          VisitEvent::EndTraverseFunction));159}160 161TEST(RecursiveASTVisitorTest, EnumDeclWithBase) {162  // Check enum and its integer base is visited.163  llvm::StringRef Code = R"cpp(164  typedef int Foo;165  enum Bar : Foo;166  )cpp";167 168  EXPECT_THAT(collectEvents(Code),169              ElementsAre(VisitEvent::StartTraverseEnum,170                          VisitEvent::StartTraverseTypedefType,171                          VisitEvent::EndTraverseTypedefType,172                          VisitEvent::EndTraverseEnum));173}174 175TEST(RecursiveASTVisitorTest, InterfaceDeclWithProtocols) {176  // Check interface and its protocols are visited.177  llvm::StringRef Code = R"cpp(178  @protocol Foo179  @end180  @protocol Bar181  @end182 183  @interface SomeObject <Foo, Bar>184  @end185  )cpp";186 187  EXPECT_THAT(collectEvents(Code, "input.m"),188              ElementsAre(VisitEvent::StartTraverseObjCProtocol,189                          VisitEvent::EndTraverseObjCProtocol,190                          VisitEvent::StartTraverseObjCProtocol,191                          VisitEvent::EndTraverseObjCProtocol,192                          VisitEvent::StartTraverseObjCInterface,193                          VisitEvent::StartTraverseObjCProtocolLoc,194                          VisitEvent::EndTraverseObjCProtocolLoc,195                          VisitEvent::StartTraverseObjCProtocolLoc,196                          VisitEvent::EndTraverseObjCProtocolLoc,197                          VisitEvent::EndTraverseObjCInterface));198}199