1 //===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Tooling/Tooling.h" 10 #include "clang/AST/ASTConsumer.h" 11 #include "clang/AST/DeclCXX.h" 12 #include "clang/AST/DeclGroup.h" 13 #include "clang/Driver/Compilation.h" 14 #include "clang/Driver/Driver.h" 15 #include "clang/Frontend/ASTUnit.h" 16 #include "clang/Frontend/CompilerInstance.h" 17 #include "clang/Frontend/FrontendAction.h" 18 #include "clang/Frontend/FrontendActions.h" 19 #include "clang/Frontend/TextDiagnosticBuffer.h" 20 #include "clang/Testing/CommandLineArgs.h" 21 #include "clang/Tooling/ArgumentsAdjusters.h" 22 #include "clang/Tooling/CompilationDatabase.h" 23 #include "llvm/ADT/STLExtras.h" 24 #include "llvm/ADT/StringRef.h" 25 #include "llvm/Support/Path.h" 26 #include "llvm/Support/TargetSelect.h" 27 #include "llvm/TargetParser/Host.h" 28 #include "gtest/gtest.h" 29 #include <algorithm> 30 #include <string> 31 #include <vector> 32 33 namespace clang { 34 namespace tooling { 35 36 namespace { 37 /// Takes an ast consumer and returns it from CreateASTConsumer. This only 38 /// works with single translation unit compilations. 39 class TestAction : public clang::ASTFrontendAction { 40 public: 41 /// Takes ownership of TestConsumer. 42 explicit TestAction(std::unique_ptr<clang::ASTConsumer> TestConsumer) 43 : TestConsumer(std::move(TestConsumer)) {} 44 45 protected: 46 std::unique_ptr<clang::ASTConsumer> 47 CreateASTConsumer(clang::CompilerInstance &compiler, 48 StringRef dummy) override { 49 /// TestConsumer will be deleted by the framework calling us. 50 return std::move(TestConsumer); 51 } 52 53 private: 54 std::unique_ptr<clang::ASTConsumer> TestConsumer; 55 }; 56 57 class FindTopLevelDeclConsumer : public clang::ASTConsumer { 58 public: 59 explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl) 60 : FoundTopLevelDecl(FoundTopLevelDecl) {} 61 bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) override { 62 *FoundTopLevelDecl = true; 63 return true; 64 } 65 private: 66 bool * const FoundTopLevelDecl; 67 }; 68 } // end namespace 69 70 TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) { 71 bool FoundTopLevelDecl = false; 72 EXPECT_TRUE(runToolOnCode( 73 std::make_unique<TestAction>( 74 std::make_unique<FindTopLevelDeclConsumer>(&FoundTopLevelDecl)), 75 "")); 76 EXPECT_FALSE(FoundTopLevelDecl); 77 } 78 79 namespace { 80 class FindClassDeclXConsumer : public clang::ASTConsumer { 81 public: 82 FindClassDeclXConsumer(bool *FoundClassDeclX) 83 : FoundClassDeclX(FoundClassDeclX) {} 84 bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) override { 85 if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>( 86 *GroupRef.begin())) { 87 if (Record->getName() == "X") { 88 *FoundClassDeclX = true; 89 } 90 } 91 return true; 92 } 93 private: 94 bool *FoundClassDeclX; 95 }; 96 bool FindClassDeclX(ASTUnit *AST) { 97 for (std::vector<Decl *>::iterator i = AST->top_level_begin(), 98 e = AST->top_level_end(); 99 i != e; ++i) { 100 if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) { 101 if (Record->getName() == "X") { 102 return true; 103 } 104 } 105 } 106 return false; 107 } 108 109 struct TestDiagnosticConsumer : public DiagnosticConsumer { 110 TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {} 111 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 112 const Diagnostic &Info) override { 113 ++NumDiagnosticsSeen; 114 } 115 unsigned NumDiagnosticsSeen; 116 }; 117 } // end namespace 118 119 TEST(runToolOnCode, FindsClassDecl) { 120 bool FoundClassDeclX = false; 121 EXPECT_TRUE(runToolOnCode( 122 std::make_unique<TestAction>( 123 std::make_unique<FindClassDeclXConsumer>(&FoundClassDeclX)), 124 "class X;")); 125 EXPECT_TRUE(FoundClassDeclX); 126 127 FoundClassDeclX = false; 128 EXPECT_TRUE(runToolOnCode( 129 std::make_unique<TestAction>( 130 std::make_unique<FindClassDeclXConsumer>(&FoundClassDeclX)), 131 "class Y;")); 132 EXPECT_FALSE(FoundClassDeclX); 133 } 134 135 TEST(buildASTFromCode, FindsClassDecl) { 136 std::unique_ptr<ASTUnit> AST = buildASTFromCode("class X;"); 137 ASSERT_TRUE(AST.get()); 138 EXPECT_TRUE(FindClassDeclX(AST.get())); 139 140 AST = buildASTFromCode("class Y;"); 141 ASSERT_TRUE(AST.get()); 142 EXPECT_FALSE(FindClassDeclX(AST.get())); 143 } 144 145 TEST(buildASTFromCode, ReportsErrors) { 146 TestDiagnosticConsumer Consumer; 147 std::unique_ptr<ASTUnit> AST = buildASTFromCodeWithArgs( 148 "int x = \"A\";", {}, "input.cc", "clang-tool", 149 std::make_shared<PCHContainerOperations>(), 150 getClangStripDependencyFileAdjuster(), FileContentMappings(), &Consumer); 151 EXPECT_TRUE(AST.get()); 152 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen); 153 } 154 155 TEST(buildASTFromCode, FileSystem) { 156 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 157 new llvm::vfs::InMemoryFileSystem); 158 InMemoryFileSystem->addFile("included_file.h", 0, 159 llvm::MemoryBuffer::getMemBufferCopy("class X;")); 160 std::unique_ptr<ASTUnit> AST = buildASTFromCodeWithArgs( 161 R"(#include "included_file.h")", {}, "input.cc", "clang-tool", 162 std::make_shared<PCHContainerOperations>(), 163 getClangStripDependencyFileAdjuster(), FileContentMappings(), nullptr, 164 InMemoryFileSystem); 165 ASSERT_TRUE(AST.get()); 166 EXPECT_TRUE(FindClassDeclX(AST.get())); 167 } 168 169 TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) { 170 std::unique_ptr<FrontendActionFactory> Factory( 171 newFrontendActionFactory<SyntaxOnlyAction>()); 172 std::unique_ptr<FrontendAction> Action(Factory->create()); 173 EXPECT_TRUE(Action.get() != nullptr); 174 } 175 176 struct IndependentFrontendActionCreator { 177 std::unique_ptr<ASTConsumer> newASTConsumer() { 178 return std::make_unique<FindTopLevelDeclConsumer>(nullptr); 179 } 180 }; 181 182 TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) { 183 IndependentFrontendActionCreator Creator; 184 std::unique_ptr<FrontendActionFactory> Factory( 185 newFrontendActionFactory(&Creator)); 186 std::unique_ptr<FrontendAction> Action(Factory->create()); 187 EXPECT_TRUE(Action.get() != nullptr); 188 } 189 190 TEST(ToolInvocation, TestMapVirtualFile) { 191 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( 192 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 193 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 194 new llvm::vfs::InMemoryFileSystem); 195 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 196 llvm::IntrusiveRefCntPtr<FileManager> Files( 197 new FileManager(FileSystemOptions(), OverlayFileSystem)); 198 std::vector<std::string> Args; 199 Args.push_back("tool-executable"); 200 Args.push_back("-Idef"); 201 Args.push_back("-fsyntax-only"); 202 Args.push_back("test.cpp"); 203 clang::tooling::ToolInvocation Invocation( 204 Args, std::make_unique<SyntaxOnlyAction>(), Files.get()); 205 InMemoryFileSystem->addFile( 206 "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n")); 207 InMemoryFileSystem->addFile("def/abc", 0, 208 llvm::MemoryBuffer::getMemBuffer("\n")); 209 EXPECT_TRUE(Invocation.run()); 210 } 211 212 TEST(ToolInvocation, TestVirtualModulesCompilation) { 213 // FIXME: Currently, this only tests that we don't exit with an error if a 214 // mapped module.modulemap is found on the include path. In the future, expand 215 // this test to run a full modules enabled compilation, so we make sure we can 216 // rerun modules compilations with a virtual file system. 217 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( 218 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 219 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 220 new llvm::vfs::InMemoryFileSystem); 221 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 222 llvm::IntrusiveRefCntPtr<FileManager> Files( 223 new FileManager(FileSystemOptions(), OverlayFileSystem)); 224 std::vector<std::string> Args; 225 Args.push_back("tool-executable"); 226 Args.push_back("-Idef"); 227 Args.push_back("-fsyntax-only"); 228 Args.push_back("test.cpp"); 229 clang::tooling::ToolInvocation Invocation( 230 Args, std::make_unique<SyntaxOnlyAction>(), Files.get()); 231 InMemoryFileSystem->addFile( 232 "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n")); 233 InMemoryFileSystem->addFile("def/abc", 0, 234 llvm::MemoryBuffer::getMemBuffer("\n")); 235 // Add a module.modulemap file in the include directory of our header, so we 236 // trigger the module.modulemap header search logic. 237 InMemoryFileSystem->addFile("def/module.modulemap", 0, 238 llvm::MemoryBuffer::getMemBuffer("\n")); 239 EXPECT_TRUE(Invocation.run()); 240 } 241 242 TEST(ToolInvocation, DiagnosticsEngineProperlyInitializedForCC1Construction) { 243 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( 244 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 245 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 246 new llvm::vfs::InMemoryFileSystem); 247 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 248 llvm::IntrusiveRefCntPtr<FileManager> Files( 249 new FileManager(FileSystemOptions(), OverlayFileSystem)); 250 251 std::vector<std::string> Args; 252 Args.push_back("tool-executable"); 253 // Unknown warning option will result in a warning. 254 Args.push_back("-fexpensive-optimizations"); 255 // Argument that will suppress the warning above. 256 Args.push_back("-Wno-ignored-optimization-argument"); 257 Args.push_back("-E"); 258 Args.push_back("test.cpp"); 259 260 clang::tooling::ToolInvocation Invocation( 261 Args, std::make_unique<SyntaxOnlyAction>(), Files.get()); 262 InMemoryFileSystem->addFile("test.cpp", 0, 263 llvm::MemoryBuffer::getMemBuffer("")); 264 TextDiagnosticBuffer Consumer; 265 Invocation.setDiagnosticConsumer(&Consumer); 266 EXPECT_TRUE(Invocation.run()); 267 // Check that the warning was ignored due to the '-Wno-xxx' argument. 268 EXPECT_EQ(std::distance(Consumer.warn_begin(), Consumer.warn_end()), 0u); 269 } 270 271 TEST(ToolInvocation, CustomDiagnosticOptionsOverwriteParsedOnes) { 272 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( 273 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 274 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 275 new llvm::vfs::InMemoryFileSystem); 276 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 277 llvm::IntrusiveRefCntPtr<FileManager> Files( 278 new FileManager(FileSystemOptions(), OverlayFileSystem)); 279 280 std::vector<std::string> Args; 281 Args.push_back("tool-executable"); 282 // Unknown warning option will result in a warning. 283 Args.push_back("-fexpensive-optimizations"); 284 // Argument that will suppress the warning above. 285 Args.push_back("-Wno-ignored-optimization-argument"); 286 Args.push_back("-E"); 287 Args.push_back("test.cpp"); 288 289 clang::tooling::ToolInvocation Invocation( 290 Args, std::make_unique<SyntaxOnlyAction>(), Files.get()); 291 InMemoryFileSystem->addFile("test.cpp", 0, 292 llvm::MemoryBuffer::getMemBuffer("")); 293 TextDiagnosticBuffer Consumer; 294 Invocation.setDiagnosticConsumer(&Consumer); 295 296 // Inject custom `DiagnosticOptions` for command-line parsing. 297 auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>(); 298 Invocation.setDiagnosticOptions(&*DiagOpts); 299 300 EXPECT_TRUE(Invocation.run()); 301 // Check that the warning was issued during command-line parsing due to the 302 // custom `DiagnosticOptions` without '-Wno-xxx'. 303 EXPECT_EQ(std::distance(Consumer.warn_begin(), Consumer.warn_end()), 1u); 304 } 305 306 struct DiagnosticConsumerExpectingSourceManager : public DiagnosticConsumer { 307 bool SawSourceManager; 308 309 DiagnosticConsumerExpectingSourceManager() : SawSourceManager(false) {} 310 311 void HandleDiagnostic(clang::DiagnosticsEngine::Level, 312 const clang::Diagnostic &info) override { 313 SawSourceManager = info.hasSourceManager(); 314 } 315 }; 316 317 TEST(ToolInvocation, DiagConsumerExpectingSourceManager) { 318 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( 319 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 320 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 321 new llvm::vfs::InMemoryFileSystem); 322 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 323 llvm::IntrusiveRefCntPtr<FileManager> Files( 324 new FileManager(FileSystemOptions(), OverlayFileSystem)); 325 std::vector<std::string> Args; 326 Args.push_back("tool-executable"); 327 // Note: intentional error; user probably meant -ferror-limit=0. 328 Args.push_back("-ferror-limit=-1"); 329 Args.push_back("-fsyntax-only"); 330 Args.push_back("test.cpp"); 331 clang::tooling::ToolInvocation Invocation( 332 Args, std::make_unique<SyntaxOnlyAction>(), Files.get()); 333 InMemoryFileSystem->addFile( 334 "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int main() {}\n")); 335 336 DiagnosticConsumerExpectingSourceManager Consumer; 337 Invocation.setDiagnosticConsumer(&Consumer); 338 339 EXPECT_TRUE(Invocation.run()); 340 EXPECT_TRUE(Consumer.SawSourceManager); 341 } 342 343 TEST(ToolInvocation, CC1Args) { 344 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( 345 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 346 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 347 new llvm::vfs::InMemoryFileSystem); 348 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 349 llvm::IntrusiveRefCntPtr<FileManager> Files( 350 new FileManager(FileSystemOptions(), OverlayFileSystem)); 351 std::vector<std::string> Args; 352 Args.push_back("tool-executable"); 353 Args.push_back("-cc1"); 354 Args.push_back("-fsyntax-only"); 355 Args.push_back("test.cpp"); 356 clang::tooling::ToolInvocation Invocation( 357 Args, std::make_unique<SyntaxOnlyAction>(), Files.get()); 358 InMemoryFileSystem->addFile( 359 "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("void foo(void);\n")); 360 EXPECT_TRUE(Invocation.run()); 361 } 362 363 TEST(ToolInvocation, CC1ArgsInvalid) { 364 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( 365 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 366 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 367 new llvm::vfs::InMemoryFileSystem); 368 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 369 llvm::IntrusiveRefCntPtr<FileManager> Files( 370 new FileManager(FileSystemOptions(), OverlayFileSystem)); 371 std::vector<std::string> Args; 372 Args.push_back("tool-executable"); 373 Args.push_back("-cc1"); 374 Args.push_back("-invalid-arg"); 375 Args.push_back("test.cpp"); 376 clang::tooling::ToolInvocation Invocation( 377 Args, std::make_unique<SyntaxOnlyAction>(), Files.get()); 378 InMemoryFileSystem->addFile( 379 "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("void foo(void);\n")); 380 EXPECT_FALSE(Invocation.run()); 381 } 382 383 namespace { 384 /// Overlays the real filesystem with the given VFS and returns the result. 385 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> 386 overlayRealFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) { 387 auto RFS = llvm::vfs::getRealFileSystem(); 388 auto OverlayFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(RFS); 389 OverlayFS->pushOverlay(VFS); 390 return OverlayFS; 391 } 392 393 struct CommandLineExtractorTest : public ::testing::Test { 394 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS; 395 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags; 396 driver::Driver Driver; 397 398 public: 399 CommandLineExtractorTest() 400 : InMemoryFS(new llvm::vfs::InMemoryFileSystem), 401 Diags(CompilerInstance::createDiagnostics(*InMemoryFS, 402 new DiagnosticOptions)), 403 Driver("clang", llvm::sys::getDefaultTargetTriple(), *Diags, 404 "clang LLVM compiler", overlayRealFS(InMemoryFS)) {} 405 406 void addFile(StringRef Name, StringRef Content) { 407 InMemoryFS->addFile(Name, 0, llvm::MemoryBuffer::getMemBuffer(Content)); 408 } 409 410 const llvm::opt::ArgStringList * 411 extractCC1Arguments(llvm::ArrayRef<const char *> Argv) { 412 const std::unique_ptr<driver::Compilation> Compilation( 413 Driver.BuildCompilation(llvm::ArrayRef(Argv))); 414 415 return getCC1Arguments(Diags.get(), Compilation.get()); 416 } 417 }; 418 } // namespace 419 420 TEST_F(CommandLineExtractorTest, AcceptOffloading) { 421 addFile("test.c", "int main() {}\n"); 422 const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0", 423 "-x", "hip", "test.c", 424 "-nogpulib", "-nogpuinc"}; 425 EXPECT_NE(extractCC1Arguments(Args), nullptr); 426 } 427 428 TEST_F(CommandLineExtractorTest, AcceptOffloadingCompile) { 429 addFile("test.c", "int main() {}\n"); 430 const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0", 431 "-c", "-x", "hip", 432 "test.c", "-nogpulib", "-nogpuinc"}; 433 EXPECT_NE(extractCC1Arguments(Args), nullptr); 434 } 435 436 TEST_F(CommandLineExtractorTest, AcceptOffloadingSyntaxOnly) { 437 addFile("test.c", "int main() {}\n"); 438 const char *Args[] = { 439 "clang", "-target", "arm64-apple-macosx11.0.0", 440 "-fsyntax-only", "-x", "hip", 441 "test.c", "-nogpulib", "-nogpuinc"}; 442 EXPECT_NE(extractCC1Arguments(Args), nullptr); 443 } 444 445 TEST_F(CommandLineExtractorTest, AcceptExternalAssembler) { 446 addFile("test.c", "int main() {}\n"); 447 const char *Args[] = { 448 "clang", "-target", "arm64-apple-macosx11.0.0", "-fno-integrated-as", 449 "-c", "test.c"}; 450 EXPECT_NE(extractCC1Arguments(Args), nullptr); 451 } 452 453 TEST_F(CommandLineExtractorTest, AcceptEmbedBitcode) { 454 addFile("test.c", "int main() {}\n"); 455 const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0", 456 "-c", "-fembed-bitcode", "test.c"}; 457 EXPECT_NE(extractCC1Arguments(Args), nullptr); 458 } 459 460 TEST_F(CommandLineExtractorTest, AcceptSaveTemps) { 461 addFile("test.c", "int main() {}\n"); 462 const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0", 463 "-c", "-save-temps", "test.c"}; 464 EXPECT_NE(extractCC1Arguments(Args), nullptr); 465 } 466 467 TEST_F(CommandLineExtractorTest, AcceptPreprocessedInputFile) { 468 addFile("test.i", "int main() {}\n"); 469 const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0", "-c", 470 "test.i"}; 471 EXPECT_NE(extractCC1Arguments(Args), nullptr); 472 } 473 474 TEST_F(CommandLineExtractorTest, RejectMultipleArchitectures) { 475 addFile("test.c", "int main() {}\n"); 476 const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0", 477 "-arch", "x86_64", "-arch", 478 "arm64", "-c", "test.c"}; 479 EXPECT_EQ(extractCC1Arguments(Args), nullptr); 480 } 481 482 TEST_F(CommandLineExtractorTest, RejectMultipleInputFiles) { 483 addFile("one.c", "void one() {}\n"); 484 addFile("two.c", "void two() {}\n"); 485 const char *Args[] = {"clang", "-target", "arm64-apple-macosx11.0.0", 486 "-c", "one.c", "two.c"}; 487 EXPECT_EQ(extractCC1Arguments(Args), nullptr); 488 } 489 490 struct VerifyEndCallback : public SourceFileCallbacks { 491 VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {} 492 bool handleBeginSource(CompilerInstance &CI) override { 493 ++BeginCalled; 494 return true; 495 } 496 void handleEndSource() override { ++EndCalled; } 497 std::unique_ptr<ASTConsumer> newASTConsumer() { 498 return std::make_unique<FindTopLevelDeclConsumer>(&Matched); 499 } 500 unsigned BeginCalled; 501 unsigned EndCalled; 502 bool Matched; 503 }; 504 505 #if !defined(_WIN32) 506 TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) { 507 VerifyEndCallback EndCallback; 508 509 FixedCompilationDatabase Compilations("/", std::vector<std::string>()); 510 std::vector<std::string> Sources; 511 Sources.push_back("/a.cc"); 512 Sources.push_back("/b.cc"); 513 ClangTool Tool(Compilations, Sources); 514 515 Tool.mapVirtualFile("/a.cc", "void a() {}"); 516 Tool.mapVirtualFile("/b.cc", "void b() {}"); 517 518 std::unique_ptr<FrontendActionFactory> Action( 519 newFrontendActionFactory(&EndCallback, &EndCallback)); 520 Tool.run(Action.get()); 521 522 EXPECT_TRUE(EndCallback.Matched); 523 EXPECT_EQ(2u, EndCallback.BeginCalled); 524 EXPECT_EQ(2u, EndCallback.EndCalled); 525 } 526 #endif 527 528 struct SkipBodyConsumer : public clang::ASTConsumer { 529 /// Skip the 'skipMe' function. 530 bool shouldSkipFunctionBody(Decl *D) override { 531 NamedDecl *F = dyn_cast<NamedDecl>(D); 532 return F && F->getNameAsString() == "skipMe"; 533 } 534 }; 535 536 struct SkipBodyAction : public clang::ASTFrontendAction { 537 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, 538 StringRef) override { 539 Compiler.getFrontendOpts().SkipFunctionBodies = true; 540 return std::make_unique<SkipBodyConsumer>(); 541 } 542 }; 543 544 TEST(runToolOnCode, TestSkipFunctionBody) { 545 std::vector<std::string> Args = {"-std=c++11"}; 546 std::vector<std::string> Args2 = {"-fno-delayed-template-parsing"}; 547 548 EXPECT_TRUE(runToolOnCode(std::make_unique<SkipBodyAction>(), 549 "int skipMe() { an_error_here }")); 550 EXPECT_FALSE(runToolOnCode(std::make_unique<SkipBodyAction>(), 551 "int skipMeNot() { an_error_here }")); 552 553 // Test constructors with initializers 554 EXPECT_TRUE(runToolOnCodeWithArgs( 555 std::make_unique<SkipBodyAction>(), 556 "struct skipMe { skipMe() : an_error() { more error } };", Args)); 557 EXPECT_TRUE(runToolOnCodeWithArgs( 558 std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe(); };" 559 "skipMe::skipMe() : an_error([](){;}) { more error }", 560 Args)); 561 EXPECT_TRUE(runToolOnCodeWithArgs( 562 std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe(); };" 563 "skipMe::skipMe() : an_error{[](){;}} { more error }", 564 Args)); 565 EXPECT_TRUE(runToolOnCodeWithArgs( 566 std::make_unique<SkipBodyAction>(), 567 "struct skipMe { skipMe(); };" 568 "skipMe::skipMe() : a<b<c>(e)>>(), f{}, g() { error }", 569 Args)); 570 EXPECT_TRUE(runToolOnCodeWithArgs( 571 std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe() : bases()... { error } };", 572 Args)); 573 574 EXPECT_FALSE(runToolOnCodeWithArgs( 575 std::make_unique<SkipBodyAction>(), "struct skipMeNot { skipMeNot() : an_error() { } };", 576 Args)); 577 EXPECT_FALSE(runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(), 578 "struct skipMeNot { skipMeNot(); };" 579 "skipMeNot::skipMeNot() : an_error() { }", 580 Args)); 581 582 // Try/catch 583 EXPECT_TRUE(runToolOnCode( 584 std::make_unique<SkipBodyAction>(), 585 "void skipMe() try { an_error() } catch(error) { error };")); 586 EXPECT_TRUE(runToolOnCode( 587 std::make_unique<SkipBodyAction>(), 588 "struct S { void skipMe() try { an_error() } catch(error) { error } };")); 589 EXPECT_TRUE( 590 runToolOnCode(std::make_unique<SkipBodyAction>(), 591 "void skipMe() try { an_error() } catch(error) { error; }" 592 "catch(error) { error } catch (error) { }")); 593 EXPECT_FALSE(runToolOnCode( 594 std::make_unique<SkipBodyAction>(), 595 "void skipMe() try something;")); // don't crash while parsing 596 597 // Template 598 EXPECT_TRUE(runToolOnCode( 599 std::make_unique<SkipBodyAction>(), "template<typename T> int skipMe() { an_error_here }" 600 "int x = skipMe<int>();")); 601 EXPECT_FALSE(runToolOnCodeWithArgs( 602 std::make_unique<SkipBodyAction>(), 603 "template<typename T> int skipMeNot() { an_error_here }", Args2)); 604 605 EXPECT_TRUE(runToolOnCodeWithArgs( 606 std::make_unique<SkipBodyAction>(), 607 "__inline __attribute__((__gnu_inline__)) void skipMe() {}", 608 {"--cuda-host-only", "-nocudainc", "-xcuda"})); 609 } 610 611 TEST(runToolOnCodeWithArgs, TestNoDepFile) { 612 llvm::SmallString<32> DepFilePath; 613 ASSERT_FALSE(llvm::sys::fs::getPotentiallyUniqueTempFileName("depfile", "d", 614 DepFilePath)); 615 std::vector<std::string> Args; 616 Args.push_back("-MMD"); 617 Args.push_back("-MT"); 618 Args.push_back(std::string(DepFilePath.str())); 619 Args.push_back("-MF"); 620 Args.push_back(std::string(DepFilePath.str())); 621 EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(), "", Args)); 622 EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str())); 623 EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str())); 624 } 625 626 struct CheckColoredDiagnosticsAction : public clang::ASTFrontendAction { 627 CheckColoredDiagnosticsAction(bool ShouldShowColor) 628 : ShouldShowColor(ShouldShowColor) {} 629 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, 630 StringRef) override { 631 if (Compiler.getDiagnosticOpts().ShowColors != ShouldShowColor) 632 Compiler.getDiagnostics().Report( 633 Compiler.getDiagnostics().getCustomDiagID( 634 DiagnosticsEngine::Fatal, 635 "getDiagnosticOpts().ShowColors != ShouldShowColor")); 636 return std::make_unique<ASTConsumer>(); 637 } 638 639 private: 640 bool ShouldShowColor = true; 641 }; 642 643 TEST(runToolOnCodeWithArgs, DiagnosticsColor) { 644 EXPECT_TRUE(runToolOnCodeWithArgs( 645 std::make_unique<CheckColoredDiagnosticsAction>(true), "", 646 {"-fcolor-diagnostics"})); 647 EXPECT_TRUE(runToolOnCodeWithArgs( 648 std::make_unique<CheckColoredDiagnosticsAction>(false), "", 649 {"-fno-color-diagnostics"})); 650 EXPECT_TRUE(runToolOnCodeWithArgs( 651 std::make_unique<CheckColoredDiagnosticsAction>(true), "", 652 {"-fno-color-diagnostics", "-fcolor-diagnostics"})); 653 EXPECT_TRUE(runToolOnCodeWithArgs( 654 std::make_unique<CheckColoredDiagnosticsAction>(false), "", 655 {"-fcolor-diagnostics", "-fno-color-diagnostics"})); 656 EXPECT_TRUE(runToolOnCodeWithArgs( 657 std::make_unique<CheckColoredDiagnosticsAction>(true), "", 658 {"-fno-color-diagnostics", "-fdiagnostics-color=always"})); 659 660 // Check that this test would fail if ShowColors is not what it should. 661 EXPECT_FALSE(runToolOnCodeWithArgs( 662 std::make_unique<CheckColoredDiagnosticsAction>(false), "", 663 {"-fcolor-diagnostics"})); 664 } 665 666 TEST(ClangToolTest, ArgumentAdjusters) { 667 FixedCompilationDatabase Compilations("/", std::vector<std::string>()); 668 669 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 670 Tool.mapVirtualFile("/a.cc", "void a() {}"); 671 672 std::unique_ptr<FrontendActionFactory> Action( 673 newFrontendActionFactory<SyntaxOnlyAction>()); 674 675 bool Found = false; 676 bool Ran = false; 677 ArgumentsAdjuster CheckSyntaxOnlyAdjuster = 678 [&Found, &Ran](const CommandLineArguments &Args, StringRef /*unused*/) { 679 Ran = true; 680 if (llvm::is_contained(Args, "-fsyntax-only")) 681 Found = true; 682 return Args; 683 }; 684 Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster); 685 Tool.run(Action.get()); 686 EXPECT_TRUE(Ran); 687 EXPECT_TRUE(Found); 688 689 Ran = Found = false; 690 Tool.clearArgumentsAdjusters(); 691 Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster); 692 Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); 693 Tool.run(Action.get()); 694 EXPECT_TRUE(Ran); 695 EXPECT_FALSE(Found); 696 } 697 698 TEST(ClangToolTest, NoDoubleSyntaxOnly) { 699 FixedCompilationDatabase Compilations("/", {"-fsyntax-only"}); 700 701 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 702 Tool.mapVirtualFile("/a.cc", "void a() {}"); 703 704 std::unique_ptr<FrontendActionFactory> Action( 705 newFrontendActionFactory<SyntaxOnlyAction>()); 706 707 size_t SyntaxOnlyCount = 0; 708 ArgumentsAdjuster CheckSyntaxOnlyAdjuster = 709 [&SyntaxOnlyCount](const CommandLineArguments &Args, 710 StringRef /*unused*/) { 711 for (llvm::StringRef Arg : Args) { 712 if (Arg == "-fsyntax-only") 713 ++SyntaxOnlyCount; 714 } 715 return Args; 716 }; 717 718 Tool.clearArgumentsAdjusters(); 719 Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); 720 Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster); 721 Tool.run(Action.get()); 722 EXPECT_EQ(SyntaxOnlyCount, 1U); 723 } 724 725 TEST(ClangToolTest, NoOutputCommands) { 726 FixedCompilationDatabase Compilations("/", {"-save-temps", "-save-temps=cwd", 727 "--save-temps", 728 "--save-temps=somedir"}); 729 730 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 731 Tool.mapVirtualFile("/a.cc", "void a() {}"); 732 733 std::unique_ptr<FrontendActionFactory> Action( 734 newFrontendActionFactory<SyntaxOnlyAction>()); 735 736 const std::vector<llvm::StringRef> OutputCommands = {"-save-temps"}; 737 bool Ran = false; 738 ArgumentsAdjuster CheckSyntaxOnlyAdjuster = 739 [&OutputCommands, &Ran](const CommandLineArguments &Args, 740 StringRef /*unused*/) { 741 for (llvm::StringRef Arg : Args) { 742 for (llvm::StringRef OutputCommand : OutputCommands) 743 EXPECT_FALSE(Arg.contains(OutputCommand)); 744 } 745 Ran = true; 746 return Args; 747 }; 748 749 Tool.clearArgumentsAdjusters(); 750 Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); 751 Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster); 752 Tool.run(Action.get()); 753 EXPECT_TRUE(Ran); 754 } 755 756 TEST(ClangToolTest, BaseVirtualFileSystemUsage) { 757 FixedCompilationDatabase Compilations("/", std::vector<std::string>()); 758 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( 759 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 760 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 761 new llvm::vfs::InMemoryFileSystem); 762 OverlayFileSystem->pushOverlay(InMemoryFileSystem); 763 764 InMemoryFileSystem->addFile( 765 "a.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int main() {}")); 766 767 ClangTool Tool(Compilations, std::vector<std::string>(1, "a.cpp"), 768 std::make_shared<PCHContainerOperations>(), OverlayFileSystem); 769 std::unique_ptr<FrontendActionFactory> Action( 770 newFrontendActionFactory<SyntaxOnlyAction>()); 771 EXPECT_EQ(0, Tool.run(Action.get())); 772 } 773 774 // Check getClangStripDependencyFileAdjuster doesn't strip args after -MD/-MMD. 775 TEST(ClangToolTest, StripDependencyFileAdjuster) { 776 FixedCompilationDatabase Compilations("/", {"-MD", "-c", "-MMD", "-w"}); 777 778 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 779 Tool.mapVirtualFile("/a.cc", "void a() {}"); 780 781 std::unique_ptr<FrontendActionFactory> Action( 782 newFrontendActionFactory<SyntaxOnlyAction>()); 783 784 CommandLineArguments FinalArgs; 785 ArgumentsAdjuster CheckFlagsAdjuster = 786 [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) { 787 FinalArgs = Args; 788 return Args; 789 }; 790 Tool.clearArgumentsAdjusters(); 791 Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); 792 Tool.appendArgumentsAdjuster(CheckFlagsAdjuster); 793 Tool.run(Action.get()); 794 795 auto HasFlag = [&FinalArgs](const std::string &Flag) { 796 return llvm::find(FinalArgs, Flag) != FinalArgs.end(); 797 }; 798 EXPECT_FALSE(HasFlag("-MD")); 799 EXPECT_FALSE(HasFlag("-MMD")); 800 EXPECT_TRUE(HasFlag("-c")); 801 EXPECT_TRUE(HasFlag("-w")); 802 } 803 804 // Check getClangStripDependencyFileAdjuster strips /showIncludes and variants 805 TEST(ClangToolTest, StripDependencyFileAdjusterShowIncludes) { 806 FixedCompilationDatabase Compilations( 807 "/", {"/showIncludes", "/showIncludes:user", "-showIncludes", 808 "-showIncludes:user", "-c"}); 809 810 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 811 Tool.mapVirtualFile("/a.cc", "void a() {}"); 812 813 std::unique_ptr<FrontendActionFactory> Action( 814 newFrontendActionFactory<SyntaxOnlyAction>()); 815 816 CommandLineArguments FinalArgs; 817 ArgumentsAdjuster CheckFlagsAdjuster = 818 [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) { 819 FinalArgs = Args; 820 return Args; 821 }; 822 Tool.clearArgumentsAdjusters(); 823 Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); 824 Tool.appendArgumentsAdjuster(CheckFlagsAdjuster); 825 Tool.run(Action.get()); 826 827 auto HasFlag = [&FinalArgs](const std::string &Flag) { 828 return llvm::find(FinalArgs, Flag) != FinalArgs.end(); 829 }; 830 EXPECT_FALSE(HasFlag("/showIncludes")); 831 EXPECT_FALSE(HasFlag("/showIncludes:user")); 832 EXPECT_FALSE(HasFlag("-showIncludes")); 833 EXPECT_FALSE(HasFlag("-showIncludes:user")); 834 EXPECT_TRUE(HasFlag("-c")); 835 } 836 837 // Check getClangStripDependencyFileAdjuster doesn't strip args when using the 838 // MSVC cl.exe driver 839 TEST(ClangToolTest, StripDependencyFileAdjusterMsvc) { 840 FixedCompilationDatabase Compilations( 841 "/", {"--driver-mode=cl", "-MD", "-MDd", "-MT", "-O1", "-MTd", "-MP"}); 842 843 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 844 Tool.mapVirtualFile("/a.cc", "void a() {}"); 845 846 std::unique_ptr<FrontendActionFactory> Action( 847 newFrontendActionFactory<SyntaxOnlyAction>()); 848 849 CommandLineArguments FinalArgs; 850 ArgumentsAdjuster CheckFlagsAdjuster = 851 [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) { 852 FinalArgs = Args; 853 return Args; 854 }; 855 Tool.clearArgumentsAdjusters(); 856 Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); 857 Tool.appendArgumentsAdjuster(CheckFlagsAdjuster); 858 Tool.run(Action.get()); 859 860 auto HasFlag = [&FinalArgs](const std::string &Flag) { 861 return llvm::find(FinalArgs, Flag) != FinalArgs.end(); 862 }; 863 EXPECT_TRUE(HasFlag("-MD")); 864 EXPECT_TRUE(HasFlag("-MDd")); 865 EXPECT_TRUE(HasFlag("-MT")); 866 EXPECT_TRUE(HasFlag("-O1")); 867 EXPECT_TRUE(HasFlag("-MTd")); 868 EXPECT_TRUE(HasFlag("-MP")); 869 } 870 871 // Check getClangStripPluginsAdjuster strips plugin related args. 872 TEST(ClangToolTest, StripPluginsAdjuster) { 873 FixedCompilationDatabase Compilations( 874 "/", {"-Xclang", "-add-plugin", "-Xclang", "random-plugin"}); 875 876 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 877 Tool.mapVirtualFile("/a.cc", "void a() {}"); 878 879 std::unique_ptr<FrontendActionFactory> Action( 880 newFrontendActionFactory<SyntaxOnlyAction>()); 881 882 CommandLineArguments FinalArgs; 883 ArgumentsAdjuster CheckFlagsAdjuster = 884 [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) { 885 FinalArgs = Args; 886 return Args; 887 }; 888 Tool.clearArgumentsAdjusters(); 889 Tool.appendArgumentsAdjuster(getStripPluginsAdjuster()); 890 Tool.appendArgumentsAdjuster(CheckFlagsAdjuster); 891 Tool.run(Action.get()); 892 893 auto HasFlag = [&FinalArgs](const std::string &Flag) { 894 return llvm::find(FinalArgs, Flag) != FinalArgs.end(); 895 }; 896 EXPECT_FALSE(HasFlag("-Xclang")); 897 EXPECT_FALSE(HasFlag("-add-plugin")); 898 EXPECT_FALSE(HasFlag("-random-plugin")); 899 } 900 901 TEST(addTargetAndModeForProgramName, AddsTargetAndMode) { 902 llvm::InitializeAllTargets(); 903 904 std::string Target = getAnyTargetForTesting(); 905 ASSERT_FALSE(Target.empty()); 906 907 std::vector<std::string> Args = {"clang", "-foo"}; 908 addTargetAndModeForProgramName(Args, ""); 909 EXPECT_EQ((std::vector<std::string>{"clang", "-foo"}), Args); 910 addTargetAndModeForProgramName(Args, Target + "-g++"); 911 EXPECT_EQ((std::vector<std::string>{"clang", "--target=" + Target, 912 "--driver-mode=g++", "-foo"}), 913 Args); 914 } 915 916 TEST(addTargetAndModeForProgramName, PathIgnored) { 917 llvm::InitializeAllTargets(); 918 std::string Target = getAnyTargetForTesting(); 919 ASSERT_FALSE(Target.empty()); 920 921 SmallString<32> ToolPath; 922 llvm::sys::path::append(ToolPath, "foo", "bar", Target + "-g++"); 923 924 std::vector<std::string> Args = {"clang", "-foo"}; 925 addTargetAndModeForProgramName(Args, ToolPath); 926 EXPECT_EQ((std::vector<std::string>{"clang", "--target=" + Target, 927 "--driver-mode=g++", "-foo"}), 928 Args); 929 } 930 931 TEST(addTargetAndModeForProgramName, IgnoresExistingTarget) { 932 llvm::InitializeAllTargets(); 933 std::string Target = getAnyTargetForTesting(); 934 ASSERT_FALSE(Target.empty()); 935 936 std::vector<std::string> Args = {"clang", "-foo", "-target", "something"}; 937 addTargetAndModeForProgramName(Args, Target + "-g++"); 938 EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo", 939 "-target", "something"}), 940 Args); 941 942 std::vector<std::string> ArgsAlt = {"clang", "-foo", "--target=something"}; 943 addTargetAndModeForProgramName(ArgsAlt, Target + "-g++"); 944 EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo", 945 "--target=something"}), 946 ArgsAlt); 947 } 948 949 TEST(addTargetAndModeForProgramName, IgnoresExistingMode) { 950 llvm::InitializeAllTargets(); 951 std::string Target = getAnyTargetForTesting(); 952 ASSERT_FALSE(Target.empty()); 953 954 std::vector<std::string> Args = {"clang", "-foo", "--driver-mode=abc"}; 955 addTargetAndModeForProgramName(Args, Target + "-g++"); 956 EXPECT_EQ((std::vector<std::string>{"clang", "--target=" + Target, "-foo", 957 "--driver-mode=abc"}), 958 Args); 959 } 960 961 #ifndef _WIN32 962 TEST(ClangToolTest, BuildASTs) { 963 FixedCompilationDatabase Compilations("/", std::vector<std::string>()); 964 965 std::vector<std::string> Sources; 966 Sources.push_back("/a.cc"); 967 Sources.push_back("/b.cc"); 968 ClangTool Tool(Compilations, Sources); 969 970 Tool.mapVirtualFile("/a.cc", "void a() {}"); 971 Tool.mapVirtualFile("/b.cc", "void b() {}"); 972 973 std::vector<std::unique_ptr<ASTUnit>> ASTs; 974 EXPECT_EQ(0, Tool.buildASTs(ASTs)); 975 EXPECT_EQ(2u, ASTs.size()); 976 } 977 978 TEST(ClangToolTest, InjectDiagnosticConsumer) { 979 FixedCompilationDatabase Compilations("/", std::vector<std::string>()); 980 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 981 Tool.mapVirtualFile("/a.cc", "int x = undeclared;"); 982 TestDiagnosticConsumer Consumer; 983 Tool.setDiagnosticConsumer(&Consumer); 984 std::unique_ptr<FrontendActionFactory> Action( 985 newFrontendActionFactory<SyntaxOnlyAction>()); 986 Tool.run(Action.get()); 987 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen); 988 } 989 990 TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) { 991 FixedCompilationDatabase Compilations("/", std::vector<std::string>()); 992 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); 993 Tool.mapVirtualFile("/a.cc", "int x = undeclared;"); 994 TestDiagnosticConsumer Consumer; 995 Tool.setDiagnosticConsumer(&Consumer); 996 std::vector<std::unique_ptr<ASTUnit>> ASTs; 997 Tool.buildASTs(ASTs); 998 EXPECT_EQ(1u, ASTs.size()); 999 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen); 1000 } 1001 #endif 1002 1003 TEST(runToolOnCode, TestResetDiagnostics) { 1004 // This is a tool that resets the diagnostic during the compilation. 1005 struct ResetDiagnosticAction : public clang::ASTFrontendAction { 1006 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, 1007 StringRef) override { 1008 struct Consumer : public clang::ASTConsumer { 1009 bool HandleTopLevelDecl(clang::DeclGroupRef D) override { 1010 auto &Diags = (*D.begin())->getASTContext().getDiagnostics(); 1011 // Ignore any error 1012 Diags.Reset(); 1013 // Disable warnings because computing the CFG might crash. 1014 Diags.setIgnoreAllWarnings(true); 1015 return true; 1016 } 1017 }; 1018 return std::make_unique<Consumer>(); 1019 } 1020 }; 1021 1022 // Should not crash 1023 EXPECT_FALSE( 1024 runToolOnCode(std::make_unique<ResetDiagnosticAction>(), 1025 "struct Foo { Foo(int); ~Foo(); struct Fwd _fwd; };" 1026 "void func() { long x; Foo f(x); }")); 1027 } 1028 1029 } // end namespace tooling 1030 } // end namespace clang 1031