DependencyScannerTest.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. #include "clang/AST/ASTConsumer.h"
  9. #include "clang/AST/DeclCXX.h"
  10. #include "clang/AST/DeclGroup.h"
  11. #include "clang/Frontend/ASTUnit.h"
  12. #include "clang/Frontend/CompilerInstance.h"
  13. #include "clang/Frontend/FrontendAction.h"
  14. #include "clang/Frontend/FrontendActions.h"
  15. #include "clang/Tooling/CompilationDatabase.h"
  16. #include "clang/Tooling/Tooling.h"
  17. #include "llvm/ADT/STLExtras.h"
  18. #include "llvm/Support/FormatVariadic.h"
  19. #include "llvm/Support/Path.h"
  20. #include "llvm/Support/TargetRegistry.h"
  21. #include "llvm/Support/TargetSelect.h"
  22. #include "gtest/gtest.h"
  23. #include <algorithm>
  24. #include <string>
  25. namespace clang {
  26. namespace tooling {
  27. namespace {
  28. /// Prints out all of the gathered dependencies into a string.
  29. class TestFileCollector : public DependencyFileGenerator {
  30. public:
  31. TestFileCollector(DependencyOutputOptions &Opts,
  32. std::vector<std::string> &Deps)
  33. : DependencyFileGenerator(Opts), Deps(Deps) {}
  34. void finishedMainFile(DiagnosticsEngine &Diags) override {
  35. auto NewDeps = getDependencies();
  36. Deps.insert(Deps.end(), NewDeps.begin(), NewDeps.end());
  37. }
  38. private:
  39. std::vector<std::string> &Deps;
  40. };
  41. class TestDependencyScanningAction : public tooling::ToolAction {
  42. public:
  43. TestDependencyScanningAction(std::vector<std::string> &Deps) : Deps(Deps) {}
  44. bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
  45. FileManager *FileMgr,
  46. std::shared_ptr<PCHContainerOperations> PCHContainerOps,
  47. DiagnosticConsumer *DiagConsumer) override {
  48. CompilerInstance Compiler(std::move(PCHContainerOps));
  49. Compiler.setInvocation(std::move(Invocation));
  50. Compiler.setFileManager(FileMgr);
  51. Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
  52. if (!Compiler.hasDiagnostics())
  53. return false;
  54. Compiler.createSourceManager(*FileMgr);
  55. Compiler.addDependencyCollector(std::make_shared<TestFileCollector>(
  56. Compiler.getInvocation().getDependencyOutputOpts(), Deps));
  57. auto Action = std::make_unique<PreprocessOnlyAction>();
  58. return Compiler.ExecuteAction(*Action);
  59. }
  60. private:
  61. std::vector<std::string> &Deps;
  62. };
  63. } // namespace
  64. TEST(DependencyScanner, ScanDepsReuseFilemanager) {
  65. std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"};
  66. StringRef CWD = "/root";
  67. FixedCompilationDatabase CDB(CWD, Compilation);
  68. auto VFS = new llvm::vfs::InMemoryFileSystem();
  69. VFS->setCurrentWorkingDirectory(CWD);
  70. auto Sept = llvm::sys::path::get_separator();
  71. std::string HeaderPath = llvm::formatv("{0}root{0}header.h", Sept);
  72. std::string SymlinkPath = llvm::formatv("{0}root{0}symlink.h", Sept);
  73. std::string TestPath = llvm::formatv("{0}root{0}test.cpp", Sept);
  74. VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n"));
  75. VFS->addHardLink(SymlinkPath, HeaderPath);
  76. VFS->addFile(TestPath, 0,
  77. llvm::MemoryBuffer::getMemBuffer(
  78. "#include \"symlink.h\"\n#include \"header.h\"\n"));
  79. ClangTool Tool(CDB, {"test.cpp"}, std::make_shared<PCHContainerOperations>(),
  80. VFS);
  81. Tool.clearArgumentsAdjusters();
  82. std::vector<std::string> Deps;
  83. TestDependencyScanningAction Action(Deps);
  84. Tool.run(&Action);
  85. using llvm::sys::path::convert_to_slash;
  86. // The first invocation should return dependencies in order of access.
  87. ASSERT_EQ(Deps.size(), 3u);
  88. EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp");
  89. EXPECT_EQ(convert_to_slash(Deps[1]), "/root/symlink.h");
  90. EXPECT_EQ(convert_to_slash(Deps[2]), "/root/header.h");
  91. // The file manager should still have two FileEntries, as one file is a
  92. // hardlink.
  93. FileManager &Files = Tool.getFiles();
  94. EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u);
  95. Deps.clear();
  96. Tool.run(&Action);
  97. // The second invocation should have the same order of dependencies.
  98. ASSERT_EQ(Deps.size(), 3u);
  99. EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp");
  100. EXPECT_EQ(convert_to_slash(Deps[1]), "/root/symlink.h");
  101. EXPECT_EQ(convert_to_slash(Deps[2]), "/root/header.h");
  102. EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u);
  103. }
  104. TEST(DependencyScanner, ScanDepsReuseFilemanagerSkippedFile) {
  105. std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"};
  106. StringRef CWD = "/root";
  107. FixedCompilationDatabase CDB(CWD, Compilation);
  108. auto VFS = new llvm::vfs::InMemoryFileSystem();
  109. VFS->setCurrentWorkingDirectory(CWD);
  110. auto Sept = llvm::sys::path::get_separator();
  111. std::string HeaderPath = llvm::formatv("{0}root{0}header.h", Sept);
  112. std::string SymlinkPath = llvm::formatv("{0}root{0}symlink.h", Sept);
  113. std::string TestPath = llvm::formatv("{0}root{0}test.cpp", Sept);
  114. std::string Test2Path = llvm::formatv("{0}root{0}test2.cpp", Sept);
  115. VFS->addFile(HeaderPath, 0,
  116. llvm::MemoryBuffer::getMemBuffer("#pragma once\n"));
  117. VFS->addHardLink(SymlinkPath, HeaderPath);
  118. VFS->addFile(TestPath, 0,
  119. llvm::MemoryBuffer::getMemBuffer(
  120. "#include \"header.h\"\n#include \"symlink.h\"\n"));
  121. VFS->addFile(Test2Path, 0,
  122. llvm::MemoryBuffer::getMemBuffer(
  123. "#include \"symlink.h\"\n#include \"header.h\"\n"));
  124. ClangTool Tool(CDB, {"test.cpp", "test2.cpp"},
  125. std::make_shared<PCHContainerOperations>(), VFS);
  126. Tool.clearArgumentsAdjusters();
  127. std::vector<std::string> Deps;
  128. TestDependencyScanningAction Action(Deps);
  129. Tool.run(&Action);
  130. using llvm::sys::path::convert_to_slash;
  131. ASSERT_EQ(Deps.size(), 6u);
  132. EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp");
  133. EXPECT_EQ(convert_to_slash(Deps[1]), "/root/header.h");
  134. EXPECT_EQ(convert_to_slash(Deps[2]), "/root/symlink.h");
  135. EXPECT_EQ(convert_to_slash(Deps[3]), "/root/test2.cpp");
  136. EXPECT_EQ(convert_to_slash(Deps[4]), "/root/symlink.h");
  137. EXPECT_EQ(convert_to_slash(Deps[5]), "/root/header.h");
  138. }
  139. TEST(DependencyScanner, ScanDepsReuseFilemanagerHasInclude) {
  140. std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"};
  141. StringRef CWD = "/root";
  142. FixedCompilationDatabase CDB(CWD, Compilation);
  143. auto VFS = new llvm::vfs::InMemoryFileSystem();
  144. VFS->setCurrentWorkingDirectory(CWD);
  145. auto Sept = llvm::sys::path::get_separator();
  146. std::string HeaderPath = llvm::formatv("{0}root{0}header.h", Sept);
  147. std::string SymlinkPath = llvm::formatv("{0}root{0}symlink.h", Sept);
  148. std::string TestPath = llvm::formatv("{0}root{0}test.cpp", Sept);
  149. VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n"));
  150. VFS->addHardLink(SymlinkPath, HeaderPath);
  151. VFS->addFile(
  152. TestPath, 0,
  153. llvm::MemoryBuffer::getMemBuffer("#if __has_include(\"header.h\") && "
  154. "__has_include(\"symlink.h\")\n#endif"));
  155. ClangTool Tool(CDB, {"test.cpp", "test.cpp"},
  156. std::make_shared<PCHContainerOperations>(), VFS);
  157. Tool.clearArgumentsAdjusters();
  158. std::vector<std::string> Deps;
  159. TestDependencyScanningAction Action(Deps);
  160. Tool.run(&Action);
  161. using llvm::sys::path::convert_to_slash;
  162. ASSERT_EQ(Deps.size(), 6u);
  163. EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp");
  164. EXPECT_EQ(convert_to_slash(Deps[1]), "/root/header.h");
  165. EXPECT_EQ(convert_to_slash(Deps[2]), "/root/symlink.h");
  166. EXPECT_EQ(convert_to_slash(Deps[3]), "/root/test.cpp");
  167. EXPECT_EQ(convert_to_slash(Deps[4]), "/root/header.h");
  168. EXPECT_EQ(convert_to_slash(Deps[5]), "/root/symlink.h");
  169. }
  170. } // end namespace tooling
  171. } // end namespace clang