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 SourceFileCallbacks {
    135   VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
    136   virtual bool handleBeginSource(CompilerInstance &CI,
    137                                  StringRef Filename) LLVM_OVERRIDE {
    138     ++BeginCalled;
    139     return true;
    140   }
    141   virtual void handleEndSource() {
    142     ++EndCalled;
    143   }
    144   ASTConsumer *newASTConsumer() {
    145     return new FindTopLevelDeclConsumer(&Matched);
    146   }
    147   unsigned BeginCalled;
    148   unsigned EndCalled;
    149   bool Matched;
    150 };
    151 
    152 #if !defined(_WIN32)
    153 TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
    154   VerifyEndCallback EndCallback;
    155 
    156   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
    157   std::vector<std::string> Sources;
    158   Sources.push_back("/a.cc");
    159   Sources.push_back("/b.cc");
    160   ClangTool Tool(Compilations, Sources);
    161 
    162   Tool.mapVirtualFile("/a.cc", "void a() {}");
    163   Tool.mapVirtualFile("/b.cc", "void b() {}");
    164 
    165   Tool.run(newFrontendActionFactory(&EndCallback, &EndCallback));
    166 
    167   EXPECT_TRUE(EndCallback.Matched);
    168   EXPECT_EQ(2u, EndCallback.BeginCalled);
    169   EXPECT_EQ(2u, EndCallback.EndCalled);
    170 }
    171 #endif
    172 
    173 struct SkipBodyConsumer : public clang::ASTConsumer {
    174   /// Skip the 'skipMe' function.
    175   virtual bool shouldSkipFunctionBody(Decl *D) {
    176     FunctionDecl *F = dyn_cast<FunctionDecl>(D);
    177     return F && F->getNameAsString() == "skipMe";
    178   }
    179 };
    180 
    181 struct SkipBodyAction : public clang::ASTFrontendAction {
    182   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
    183                                          StringRef) {
    184     Compiler.getFrontendOpts().SkipFunctionBodies = true;
    185     return new SkipBodyConsumer;
    186   }
    187 };
    188 
    189 TEST(runToolOnCode, TestSkipFunctionBody) {
    190   EXPECT_TRUE(runToolOnCode(new SkipBodyAction,
    191                             "int skipMe() { an_error_here }"));
    192   EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
    193                              "int skipMeNot() { an_error_here }"));
    194 }
    195 
    196 struct CheckSyntaxOnlyAdjuster: public ArgumentsAdjuster {
    197   bool &Found;
    198   bool &Ran;
    199 
    200   CheckSyntaxOnlyAdjuster(bool &Found, bool &Ran) : Found(Found), Ran(Ran) { }
    201 
    202   virtual CommandLineArguments
    203   Adjust(const CommandLineArguments &Args) LLVM_OVERRIDE {
    204     Ran = true;
    205     for (unsigned I = 0, E = Args.size(); I != E; ++I) {
    206       if (Args[I] == "-fsyntax-only") {
    207         Found = true;
    208         break;
    209       }
    210     }
    211     return Args;
    212   }
    213 };
    214 
    215 TEST(ClangToolTest, ArgumentAdjusters) {
    216   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
    217 
    218   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
    219   Tool.mapVirtualFile("/a.cc", "void a() {}");
    220 
    221   bool Found = false;
    222   bool Ran = false;
    223   Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
    224   Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
    225   EXPECT_TRUE(Ran);
    226   EXPECT_TRUE(Found);
    227 
    228   Ran = Found = false;
    229   Tool.clearArgumentsAdjusters();
    230   Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
    231   Tool.appendArgumentsAdjuster(new ClangSyntaxOnlyAdjuster());
    232   Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
    233   EXPECT_TRUE(Ran);
    234   EXPECT_FALSE(Found);
    235 }
    236 
    237 } // end namespace tooling
    238 } // end namespace clang
    239