From c11976f525f3b9b9dc6080f0b23d2ef1ec5fe8fd Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 12 Apr 2024 10:26:58 -0700 Subject: [clang][deps] Create separate unittest directory This is an NFC change split from https://github.com/llvm/llvm-project/pull/68645. --- clang/unittests/Tooling/CMakeLists.txt | 2 +- clang/unittests/Tooling/DependencyScannerTest.cpp | 303 --------------------- .../DependencyScanning/DependencyScannerTest.cpp | 303 +++++++++++++++++++++ 3 files changed, 304 insertions(+), 304 deletions(-) delete mode 100644 clang/unittests/Tooling/DependencyScannerTest.cpp create mode 100644 clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp diff --git a/clang/unittests/Tooling/CMakeLists.txt b/clang/unittests/Tooling/CMakeLists.txt index 5a10a6b..2ff493e 100644 --- a/clang/unittests/Tooling/CMakeLists.txt +++ b/clang/unittests/Tooling/CMakeLists.txt @@ -13,7 +13,6 @@ add_clang_unittest(ToolingTests CastExprTest.cpp CommentHandlerTest.cpp CompilationDatabaseTest.cpp - DependencyScannerTest.cpp DiagnosticsYamlTest.cpp ExecutionTest.cpp FixItTest.cpp @@ -24,6 +23,7 @@ add_clang_unittest(ToolingTests LookupTest.cpp QualTypeNamesTest.cpp RangeSelectorTest.cpp + DependencyScanning/DependencyScannerTest.cpp RecursiveASTVisitorTests/Attr.cpp RecursiveASTVisitorTests/BitfieldInitializer.cpp RecursiveASTVisitorTests/CallbacksLeaf.cpp diff --git a/clang/unittests/Tooling/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScannerTest.cpp deleted file mode 100644 index 8735fca..0000000 --- a/clang/unittests/Tooling/DependencyScannerTest.cpp +++ /dev/null @@ -1,303 +0,0 @@ -//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclGroup.h" -#include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendAction.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/CompilationDatabase.h" -#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/MC/TargetRegistry.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Testing/Support/Error.h" -#include "gtest/gtest.h" -#include -#include - -using namespace clang; -using namespace tooling; -using namespace dependencies; - -namespace { - -/// Prints out all of the gathered dependencies into a string. -class TestFileCollector : public DependencyFileGenerator { -public: - TestFileCollector(DependencyOutputOptions &Opts, - std::vector &Deps) - : DependencyFileGenerator(Opts), Deps(Deps) {} - - void finishedMainFile(DiagnosticsEngine &Diags) override { - auto NewDeps = getDependencies(); - Deps.insert(Deps.end(), NewDeps.begin(), NewDeps.end()); - } - -private: - std::vector &Deps; -}; - -class TestDependencyScanningAction : public tooling::ToolAction { -public: - TestDependencyScanningAction(std::vector &Deps) : Deps(Deps) {} - - bool runInvocation(std::shared_ptr Invocation, - FileManager *FileMgr, - std::shared_ptr PCHContainerOps, - DiagnosticConsumer *DiagConsumer) override { - CompilerInstance Compiler(std::move(PCHContainerOps)); - Compiler.setInvocation(std::move(Invocation)); - Compiler.setFileManager(FileMgr); - - Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); - if (!Compiler.hasDiagnostics()) - return false; - - Compiler.createSourceManager(*FileMgr); - Compiler.addDependencyCollector(std::make_shared( - Compiler.getInvocation().getDependencyOutputOpts(), Deps)); - - auto Action = std::make_unique(); - return Compiler.ExecuteAction(*Action); - } - -private: - std::vector &Deps; -}; - -} // namespace - -TEST(DependencyScanner, ScanDepsReuseFilemanager) { - std::vector Compilation = {"-c", "-E", "-MT", "test.cpp.o"}; - StringRef CWD = "/root"; - FixedCompilationDatabase CDB(CWD, Compilation); - - auto VFS = new llvm::vfs::InMemoryFileSystem(); - VFS->setCurrentWorkingDirectory(CWD); - auto Sept = llvm::sys::path::get_separator(); - std::string HeaderPath = - std::string(llvm::formatv("{0}root{0}header.h", Sept)); - std::string SymlinkPath = - std::string(llvm::formatv("{0}root{0}symlink.h", Sept)); - std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept)); - - VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n")); - VFS->addHardLink(SymlinkPath, HeaderPath); - VFS->addFile(TestPath, 0, - llvm::MemoryBuffer::getMemBuffer( - "#include \"symlink.h\"\n#include \"header.h\"\n")); - - ClangTool Tool(CDB, {"test.cpp"}, std::make_shared(), - VFS); - Tool.clearArgumentsAdjusters(); - std::vector Deps; - TestDependencyScanningAction Action(Deps); - Tool.run(&Action); - using llvm::sys::path::convert_to_slash; - // The first invocation should return dependencies in order of access. - ASSERT_EQ(Deps.size(), 3u); - EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp"); - EXPECT_EQ(convert_to_slash(Deps[1]), "/root/symlink.h"); - EXPECT_EQ(convert_to_slash(Deps[2]), "/root/header.h"); - - // The file manager should still have two FileEntries, as one file is a - // hardlink. - FileManager &Files = Tool.getFiles(); - EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u); - - Deps.clear(); - Tool.run(&Action); - // The second invocation should have the same order of dependencies. - ASSERT_EQ(Deps.size(), 3u); - EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp"); - EXPECT_EQ(convert_to_slash(Deps[1]), "/root/symlink.h"); - EXPECT_EQ(convert_to_slash(Deps[2]), "/root/header.h"); - - EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u); -} - -TEST(DependencyScanner, ScanDepsReuseFilemanagerSkippedFile) { - std::vector Compilation = {"-c", "-E", "-MT", "test.cpp.o"}; - StringRef CWD = "/root"; - FixedCompilationDatabase CDB(CWD, Compilation); - - auto VFS = new llvm::vfs::InMemoryFileSystem(); - VFS->setCurrentWorkingDirectory(CWD); - auto Sept = llvm::sys::path::get_separator(); - std::string HeaderPath = - std::string(llvm::formatv("{0}root{0}header.h", Sept)); - std::string SymlinkPath = - std::string(llvm::formatv("{0}root{0}symlink.h", Sept)); - std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept)); - std::string Test2Path = - std::string(llvm::formatv("{0}root{0}test2.cpp", Sept)); - - VFS->addFile(HeaderPath, 0, - llvm::MemoryBuffer::getMemBuffer("#pragma once\n")); - VFS->addHardLink(SymlinkPath, HeaderPath); - VFS->addFile(TestPath, 0, - llvm::MemoryBuffer::getMemBuffer( - "#include \"header.h\"\n#include \"symlink.h\"\n")); - VFS->addFile(Test2Path, 0, - llvm::MemoryBuffer::getMemBuffer( - "#include \"symlink.h\"\n#include \"header.h\"\n")); - - ClangTool Tool(CDB, {"test.cpp", "test2.cpp"}, - std::make_shared(), VFS); - Tool.clearArgumentsAdjusters(); - std::vector Deps; - TestDependencyScanningAction Action(Deps); - Tool.run(&Action); - using llvm::sys::path::convert_to_slash; - ASSERT_EQ(Deps.size(), 6u); - EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp"); - EXPECT_EQ(convert_to_slash(Deps[1]), "/root/header.h"); - EXPECT_EQ(convert_to_slash(Deps[2]), "/root/symlink.h"); - EXPECT_EQ(convert_to_slash(Deps[3]), "/root/test2.cpp"); - EXPECT_EQ(convert_to_slash(Deps[4]), "/root/symlink.h"); - EXPECT_EQ(convert_to_slash(Deps[5]), "/root/header.h"); -} - -TEST(DependencyScanner, ScanDepsReuseFilemanagerHasInclude) { - std::vector Compilation = {"-c", "-E", "-MT", "test.cpp.o"}; - StringRef CWD = "/root"; - FixedCompilationDatabase CDB(CWD, Compilation); - - auto VFS = new llvm::vfs::InMemoryFileSystem(); - VFS->setCurrentWorkingDirectory(CWD); - auto Sept = llvm::sys::path::get_separator(); - std::string HeaderPath = - std::string(llvm::formatv("{0}root{0}header.h", Sept)); - std::string SymlinkPath = - std::string(llvm::formatv("{0}root{0}symlink.h", Sept)); - std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept)); - - VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n")); - VFS->addHardLink(SymlinkPath, HeaderPath); - VFS->addFile( - TestPath, 0, - llvm::MemoryBuffer::getMemBuffer("#if __has_include(\"header.h\") && " - "__has_include(\"symlink.h\")\n#endif")); - - ClangTool Tool(CDB, {"test.cpp", "test.cpp"}, - std::make_shared(), VFS); - Tool.clearArgumentsAdjusters(); - std::vector Deps; - TestDependencyScanningAction Action(Deps); - Tool.run(&Action); - using llvm::sys::path::convert_to_slash; - ASSERT_EQ(Deps.size(), 6u); - EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp"); - EXPECT_EQ(convert_to_slash(Deps[1]), "/root/header.h"); - EXPECT_EQ(convert_to_slash(Deps[2]), "/root/symlink.h"); - EXPECT_EQ(convert_to_slash(Deps[3]), "/root/test.cpp"); - EXPECT_EQ(convert_to_slash(Deps[4]), "/root/header.h"); - EXPECT_EQ(convert_to_slash(Deps[5]), "/root/symlink.h"); -} - -TEST(DependencyScanner, ScanDepsWithFS) { - std::vector CommandLine = {"clang", - "-target", - "x86_64-apple-macosx10.7", - "-c", - "test.cpp", - "-o" - "test.cpp.o"}; - StringRef CWD = "/root"; - - auto VFS = new llvm::vfs::InMemoryFileSystem(); - VFS->setCurrentWorkingDirectory(CWD); - auto Sept = llvm::sys::path::get_separator(); - std::string HeaderPath = - std::string(llvm::formatv("{0}root{0}header.h", Sept)); - std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept)); - - VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n")); - VFS->addFile(TestPath, 0, - llvm::MemoryBuffer::getMemBuffer("#include \"header.h\"\n")); - - DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, - ScanningOutputFormat::Make); - DependencyScanningTool ScanTool(Service, VFS); - - std::string DepFile; - ASSERT_THAT_ERROR( - ScanTool.getDependencyFile(CommandLine, CWD).moveInto(DepFile), - llvm::Succeeded()); - using llvm::sys::path::convert_to_slash; - EXPECT_EQ(convert_to_slash(DepFile), - "test.cpp.o: /root/test.cpp /root/header.h\n"); -} - -TEST(DependencyScanner, ScanDepsWithModuleLookup) { - std::vector CommandLine = { - "clang", - "-target", - "x86_64-apple-macosx10.7", - "-c", - "test.m", - "-o" - "test.m.o", - "-fmodules", - "-I/root/SomeSources", - }; - StringRef CWD = "/root"; - - auto VFS = new llvm::vfs::InMemoryFileSystem(); - VFS->setCurrentWorkingDirectory(CWD); - auto Sept = llvm::sys::path::get_separator(); - std::string OtherPath = - std::string(llvm::formatv("{0}root{0}SomeSources{0}other.h", Sept)); - std::string TestPath = std::string(llvm::formatv("{0}root{0}test.m", Sept)); - - VFS->addFile(OtherPath, 0, llvm::MemoryBuffer::getMemBuffer("\n")); - VFS->addFile(TestPath, 0, llvm::MemoryBuffer::getMemBuffer("@import Foo;\n")); - - struct InterceptorFS : llvm::vfs::ProxyFileSystem { - std::vector StatPaths; - std::vector ReadFiles; - - InterceptorFS(IntrusiveRefCntPtr UnderlyingFS) - : ProxyFileSystem(UnderlyingFS) {} - - llvm::ErrorOr status(const Twine &Path) override { - StatPaths.push_back(Path.str()); - return ProxyFileSystem::status(Path); - } - - llvm::ErrorOr> - openFileForRead(const Twine &Path) override { - ReadFiles.push_back(Path.str()); - return ProxyFileSystem::openFileForRead(Path); - } - }; - - auto InterceptFS = llvm::makeIntrusiveRefCnt(VFS); - - DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, - ScanningOutputFormat::Make); - DependencyScanningTool ScanTool(Service, InterceptFS); - - // This will fail with "fatal error: module 'Foo' not found" but it doesn't - // matter, the point of the test is to check that files are not read - // unnecessarily. - std::string DepFile; - ASSERT_THAT_ERROR( - ScanTool.getDependencyFile(CommandLine, CWD).moveInto(DepFile), - llvm::Failed()); - - EXPECT_TRUE(llvm::find(InterceptFS->StatPaths, OtherPath) == - InterceptFS->StatPaths.end()); - EXPECT_EQ(InterceptFS->ReadFiles, std::vector{"test.m"}); -} diff --git a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp new file mode 100644 index 0000000..ec0e143 --- /dev/null +++ b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp @@ -0,0 +1,303 @@ +//===- DependencyScannerTest.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +using namespace clang; +using namespace tooling; +using namespace dependencies; + +namespace { + +/// Prints out all of the gathered dependencies into a string. +class TestFileCollector : public DependencyFileGenerator { +public: + TestFileCollector(DependencyOutputOptions &Opts, + std::vector &Deps) + : DependencyFileGenerator(Opts), Deps(Deps) {} + + void finishedMainFile(DiagnosticsEngine &Diags) override { + auto NewDeps = getDependencies(); + Deps.insert(Deps.end(), NewDeps.begin(), NewDeps.end()); + } + +private: + std::vector &Deps; +}; + +class TestDependencyScanningAction : public tooling::ToolAction { +public: + TestDependencyScanningAction(std::vector &Deps) : Deps(Deps) {} + + bool runInvocation(std::shared_ptr Invocation, + FileManager *FileMgr, + std::shared_ptr PCHContainerOps, + DiagnosticConsumer *DiagConsumer) override { + CompilerInstance Compiler(std::move(PCHContainerOps)); + Compiler.setInvocation(std::move(Invocation)); + Compiler.setFileManager(FileMgr); + + Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); + if (!Compiler.hasDiagnostics()) + return false; + + Compiler.createSourceManager(*FileMgr); + Compiler.addDependencyCollector(std::make_shared( + Compiler.getInvocation().getDependencyOutputOpts(), Deps)); + + auto Action = std::make_unique(); + return Compiler.ExecuteAction(*Action); + } + +private: + std::vector &Deps; +}; + +} // namespace + +TEST(DependencyScanner, ScanDepsReuseFilemanager) { + std::vector Compilation = {"-c", "-E", "-MT", "test.cpp.o"}; + StringRef CWD = "/root"; + FixedCompilationDatabase CDB(CWD, Compilation); + + auto VFS = new llvm::vfs::InMemoryFileSystem(); + VFS->setCurrentWorkingDirectory(CWD); + auto Sept = llvm::sys::path::get_separator(); + std::string HeaderPath = + std::string(llvm::formatv("{0}root{0}header.h", Sept)); + std::string SymlinkPath = + std::string(llvm::formatv("{0}root{0}symlink.h", Sept)); + std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept)); + + VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n")); + VFS->addHardLink(SymlinkPath, HeaderPath); + VFS->addFile(TestPath, 0, + llvm::MemoryBuffer::getMemBuffer( + "#include \"symlink.h\"\n#include \"header.h\"\n")); + + ClangTool Tool(CDB, {"test.cpp"}, std::make_shared(), + VFS); + Tool.clearArgumentsAdjusters(); + std::vector Deps; + TestDependencyScanningAction Action(Deps); + Tool.run(&Action); + using llvm::sys::path::convert_to_slash; + // The first invocation should return dependencies in order of access. + ASSERT_EQ(Deps.size(), 3u); + EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp"); + EXPECT_EQ(convert_to_slash(Deps[1]), "/root/symlink.h"); + EXPECT_EQ(convert_to_slash(Deps[2]), "/root/header.h"); + + // The file manager should still have two FileEntries, as one file is a + // hardlink. + FileManager &Files = Tool.getFiles(); + EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u); + + Deps.clear(); + Tool.run(&Action); + // The second invocation should have the same order of dependencies. + ASSERT_EQ(Deps.size(), 3u); + EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp"); + EXPECT_EQ(convert_to_slash(Deps[1]), "/root/symlink.h"); + EXPECT_EQ(convert_to_slash(Deps[2]), "/root/header.h"); + + EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u); +} + +TEST(DependencyScanner, ScanDepsReuseFilemanagerSkippedFile) { + std::vector Compilation = {"-c", "-E", "-MT", "test.cpp.o"}; + StringRef CWD = "/root"; + FixedCompilationDatabase CDB(CWD, Compilation); + + auto VFS = new llvm::vfs::InMemoryFileSystem(); + VFS->setCurrentWorkingDirectory(CWD); + auto Sept = llvm::sys::path::get_separator(); + std::string HeaderPath = + std::string(llvm::formatv("{0}root{0}header.h", Sept)); + std::string SymlinkPath = + std::string(llvm::formatv("{0}root{0}symlink.h", Sept)); + std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept)); + std::string Test2Path = + std::string(llvm::formatv("{0}root{0}test2.cpp", Sept)); + + VFS->addFile(HeaderPath, 0, + llvm::MemoryBuffer::getMemBuffer("#pragma once\n")); + VFS->addHardLink(SymlinkPath, HeaderPath); + VFS->addFile(TestPath, 0, + llvm::MemoryBuffer::getMemBuffer( + "#include \"header.h\"\n#include \"symlink.h\"\n")); + VFS->addFile(Test2Path, 0, + llvm::MemoryBuffer::getMemBuffer( + "#include \"symlink.h\"\n#include \"header.h\"\n")); + + ClangTool Tool(CDB, {"test.cpp", "test2.cpp"}, + std::make_shared(), VFS); + Tool.clearArgumentsAdjusters(); + std::vector Deps; + TestDependencyScanningAction Action(Deps); + Tool.run(&Action); + using llvm::sys::path::convert_to_slash; + ASSERT_EQ(Deps.size(), 6u); + EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp"); + EXPECT_EQ(convert_to_slash(Deps[1]), "/root/header.h"); + EXPECT_EQ(convert_to_slash(Deps[2]), "/root/symlink.h"); + EXPECT_EQ(convert_to_slash(Deps[3]), "/root/test2.cpp"); + EXPECT_EQ(convert_to_slash(Deps[4]), "/root/symlink.h"); + EXPECT_EQ(convert_to_slash(Deps[5]), "/root/header.h"); +} + +TEST(DependencyScanner, ScanDepsReuseFilemanagerHasInclude) { + std::vector Compilation = {"-c", "-E", "-MT", "test.cpp.o"}; + StringRef CWD = "/root"; + FixedCompilationDatabase CDB(CWD, Compilation); + + auto VFS = new llvm::vfs::InMemoryFileSystem(); + VFS->setCurrentWorkingDirectory(CWD); + auto Sept = llvm::sys::path::get_separator(); + std::string HeaderPath = + std::string(llvm::formatv("{0}root{0}header.h", Sept)); + std::string SymlinkPath = + std::string(llvm::formatv("{0}root{0}symlink.h", Sept)); + std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept)); + + VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n")); + VFS->addHardLink(SymlinkPath, HeaderPath); + VFS->addFile( + TestPath, 0, + llvm::MemoryBuffer::getMemBuffer("#if __has_include(\"header.h\") && " + "__has_include(\"symlink.h\")\n#endif")); + + ClangTool Tool(CDB, {"test.cpp", "test.cpp"}, + std::make_shared(), VFS); + Tool.clearArgumentsAdjusters(); + std::vector Deps; + TestDependencyScanningAction Action(Deps); + Tool.run(&Action); + using llvm::sys::path::convert_to_slash; + ASSERT_EQ(Deps.size(), 6u); + EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp"); + EXPECT_EQ(convert_to_slash(Deps[1]), "/root/header.h"); + EXPECT_EQ(convert_to_slash(Deps[2]), "/root/symlink.h"); + EXPECT_EQ(convert_to_slash(Deps[3]), "/root/test.cpp"); + EXPECT_EQ(convert_to_slash(Deps[4]), "/root/header.h"); + EXPECT_EQ(convert_to_slash(Deps[5]), "/root/symlink.h"); +} + +TEST(DependencyScanner, ScanDepsWithFS) { + std::vector CommandLine = {"clang", + "-target", + "x86_64-apple-macosx10.7", + "-c", + "test.cpp", + "-o" + "test.cpp.o"}; + StringRef CWD = "/root"; + + auto VFS = new llvm::vfs::InMemoryFileSystem(); + VFS->setCurrentWorkingDirectory(CWD); + auto Sept = llvm::sys::path::get_separator(); + std::string HeaderPath = + std::string(llvm::formatv("{0}root{0}header.h", Sept)); + std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept)); + + VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n")); + VFS->addFile(TestPath, 0, + llvm::MemoryBuffer::getMemBuffer("#include \"header.h\"\n")); + + DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, + ScanningOutputFormat::Make); + DependencyScanningTool ScanTool(Service, VFS); + + std::string DepFile; + ASSERT_THAT_ERROR( + ScanTool.getDependencyFile(CommandLine, CWD).moveInto(DepFile), + llvm::Succeeded()); + using llvm::sys::path::convert_to_slash; + EXPECT_EQ(convert_to_slash(DepFile), + "test.cpp.o: /root/test.cpp /root/header.h\n"); +} + +TEST(DependencyScanner, ScanDepsWithModuleLookup) { + std::vector CommandLine = { + "clang", + "-target", + "x86_64-apple-macosx10.7", + "-c", + "test.m", + "-o" + "test.m.o", + "-fmodules", + "-I/root/SomeSources", + }; + StringRef CWD = "/root"; + + auto VFS = new llvm::vfs::InMemoryFileSystem(); + VFS->setCurrentWorkingDirectory(CWD); + auto Sept = llvm::sys::path::get_separator(); + std::string OtherPath = + std::string(llvm::formatv("{0}root{0}SomeSources{0}other.h", Sept)); + std::string TestPath = std::string(llvm::formatv("{0}root{0}test.m", Sept)); + + VFS->addFile(OtherPath, 0, llvm::MemoryBuffer::getMemBuffer("\n")); + VFS->addFile(TestPath, 0, llvm::MemoryBuffer::getMemBuffer("@import Foo;\n")); + + struct InterceptorFS : llvm::vfs::ProxyFileSystem { + std::vector StatPaths; + std::vector ReadFiles; + + InterceptorFS(IntrusiveRefCntPtr UnderlyingFS) + : ProxyFileSystem(UnderlyingFS) {} + + llvm::ErrorOr status(const Twine &Path) override { + StatPaths.push_back(Path.str()); + return ProxyFileSystem::status(Path); + } + + llvm::ErrorOr> + openFileForRead(const Twine &Path) override { + ReadFiles.push_back(Path.str()); + return ProxyFileSystem::openFileForRead(Path); + } + }; + + auto InterceptFS = llvm::makeIntrusiveRefCnt(VFS); + + DependencyScanningService Service(ScanningMode::DependencyDirectivesScan, + ScanningOutputFormat::Make); + DependencyScanningTool ScanTool(Service, InterceptFS); + + // This will fail with "fatal error: module 'Foo' not found" but it doesn't + // matter, the point of the test is to check that files are not read + // unnecessarily. + std::string DepFile; + ASSERT_THAT_ERROR( + ScanTool.getDependencyFile(CommandLine, CWD).moveInto(DepFile), + llvm::Failed()); + + EXPECT_TRUE(llvm::find(InterceptFS->StatPaths, OtherPath) == + InterceptFS->StatPaths.end()); + EXPECT_EQ(InterceptFS->ReadFiles, std::vector{"test.m"}); +} -- cgit v1.1