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