Home | History | Annotate | Download | only in Tooling
      1 //===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "clang/AST/ASTConsumer.h"
     11 #include "clang/AST/DeclCXX.h"
     12 #include "clang/AST/DeclGroup.h"
     13 #include "clang/Frontend/CompilerInstance.h"
     14 #include "clang/Frontend/FrontendAction.h"
     15 #include "clang/Frontend/FrontendActions.h"
     16 #include "clang/Tooling/CompilationDatabase.h"
     17 #include "clang/Tooling/Tooling.h"
     18 #include "gtest/gtest.h"
     19 #include <string>
     20 
     21 namespace clang {
     22 namespace tooling {
     23 
     24 namespace {
     25 /// Takes an ast consumer and returns it from CreateASTConsumer. This only
     26 /// works with single translation unit compilations.
     27 class TestAction : public clang::ASTFrontendAction {
     28  public:
     29   /// Takes ownership of TestConsumer.
     30   explicit TestAction(clang::ASTConsumer *TestConsumer)
     31       : TestConsumer(TestConsumer) {}
     32 
     33  protected:
     34   virtual clang::ASTConsumer* CreateASTConsumer(
     35       clang::CompilerInstance& compiler, StringRef dummy) {
     36     /// TestConsumer will be deleted by the framework calling us.
     37     return TestConsumer;
     38   }
     39 
     40  private:
     41   clang::ASTConsumer * const TestConsumer;
     42 };
     43 
     44 class FindTopLevelDeclConsumer : public clang::ASTConsumer {
     45  public:
     46   explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
     47       : FoundTopLevelDecl(FoundTopLevelDecl) {}
     48   virtual bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) {
     49     *FoundTopLevelDecl = true;
     50     return true;
     51   }
     52  private:
     53   bool * const FoundTopLevelDecl;
     54 };
     55 } // end namespace
     56 
     57 TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
     58   bool FoundTopLevelDecl = false;
     59   EXPECT_TRUE(runToolOnCode(
     60       new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), ""));
     61 #if !defined(_MSC_VER)
     62   EXPECT_FALSE(FoundTopLevelDecl);
     63 #else
     64   // FIXME: LangOpts.MicrosoftExt appends "class type_info;"
     65   EXPECT_TRUE(FoundTopLevelDecl);
     66 #endif
     67 }
     68 
     69 namespace {
     70 class FindClassDeclXConsumer : public clang::ASTConsumer {
     71  public:
     72   FindClassDeclXConsumer(bool *FoundClassDeclX)
     73       : FoundClassDeclX(FoundClassDeclX) {}
     74   virtual bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) {
     75     if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
     76             *GroupRef.begin())) {
     77       if (Record->getName() == "X") {
     78         *FoundClassDeclX = true;
     79       }
     80     }
     81     return true;
     82   }
     83  private:
     84   bool *FoundClassDeclX;
     85 };
     86 } // end namespace
     87 
     88 TEST(runToolOnCode, FindsClassDecl) {
     89   bool FoundClassDeclX = false;
     90   EXPECT_TRUE(runToolOnCode(new TestAction(
     91       new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;"));
     92   EXPECT_TRUE(FoundClassDeclX);
     93 
     94   FoundClassDeclX = false;
     95   EXPECT_TRUE(runToolOnCode(new TestAction(
     96       new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;"));
     97   EXPECT_FALSE(FoundClassDeclX);
     98 }
     99 
    100 TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
    101   OwningPtr<FrontendActionFactory> Factory(
    102       newFrontendActionFactory<SyntaxOnlyAction>());
    103   OwningPtr<FrontendAction> Action(Factory->create());
    104   EXPECT_TRUE(Action.get() != NULL);
    105 }
    106 
    107 struct IndependentFrontendActionCreator {
    108   ASTConsumer *newASTConsumer() {
    109     return new FindTopLevelDeclConsumer(NULL);
    110   }
    111 };
    112 
    113 TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
    114   IndependentFrontendActionCreator Creator;
    115   OwningPtr<FrontendActionFactory> Factory(
    116       newFrontendActionFactory(&Creator));
    117   OwningPtr<FrontendAction> Action(Factory->create());
    118   EXPECT_TRUE(Action.get() != NULL);
    119 }
    120 
    121 TEST(ToolInvocation, TestMapVirtualFile) {
    122   clang::FileManager Files((clang::FileSystemOptions()));
    123   std::vector<std::string> Args;
    124   Args.push_back("tool-executable");
    125   Args.push_back("-Idef");
    126   Args.push_back("-fsyntax-only");
    127   Args.push_back("test.cpp");
    128   clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, &Files);
    129   Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
    130   Invocation.mapVirtualFile("def/abc", "\n");
    131   EXPECT_TRUE(Invocation.run());
    132 }
    133 
    134 struct VerifyEndCallback : public EndOfSourceFileCallback {
    135   VerifyEndCallback() : Called(0), Matched(false) {}
    136   virtual void run() {
    137     ++Called;
    138   }
    139   ASTConsumer *newASTConsumer() {
    140     return new FindTopLevelDeclConsumer(&Matched);
    141   }
    142   unsigned Called;
    143   bool Matched;
    144 };
    145 
    146 #if !defined(_WIN32)
    147 TEST(newFrontendActionFactory, InjectsEndOfSourceFileCallback) {
    148   VerifyEndCallback EndCallback;
    149 
    150   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
    151   std::vector<std::string> Sources;
    152   Sources.push_back("/a.cc");
    153   Sources.push_back("/b.cc");
    154   ClangTool Tool(Compilations, Sources);
    155 
    156   Tool.mapVirtualFile("/a.cc", "void a() {}");
    157   Tool.mapVirtualFile("/b.cc", "void b() {}");
    158 
    159   Tool.run(newFrontendActionFactory(&EndCallback, &EndCallback));
    160 
    161   EXPECT_TRUE(EndCallback.Matched);
    162   EXPECT_EQ(2u, EndCallback.Called);
    163 }
    164 #endif
    165 
    166 struct SkipBodyConsumer : public clang::ASTConsumer {
    167   /// Skip the 'skipMe' function.
    168   virtual bool shouldSkipFunctionBody(Decl *D) {
    169     FunctionDecl *F = dyn_cast<FunctionDecl>(D);
    170     return F && F->getNameAsString() == "skipMe";
    171   }
    172 };
    173 
    174 struct SkipBodyAction : public clang::ASTFrontendAction {
    175   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
    176                                          StringRef) {
    177     Compiler.getFrontendOpts().SkipFunctionBodies = true;
    178     return new SkipBodyConsumer;
    179   }
    180 };
    181 
    182 TEST(runToolOnCode, TestSkipFunctionBody) {
    183   EXPECT_TRUE(runToolOnCode(new SkipBodyAction,
    184                             "int skipMe() { an_error_here }"));
    185   EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
    186                              "int skipMeNot() { an_error_here }"));
    187 }
    188 
    189 } // end namespace tooling
    190 } // end namespace clang
    191