diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -1917,6 +1917,8 @@ llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { + if (Dir->type() == llvm::sys::fs::file_type::regular_file) + continue; bool IsFramework = llvm::sys::path::extension(Dir->path()) == ".framework"; if (IsFramework == SearchDir.isFramework()) loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(), diff --git a/clang/unittests/Tooling/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScannerTest.cpp --- a/clang/unittests/Tooling/DependencyScannerTest.cpp +++ b/clang/unittests/Tooling/DependencyScannerTest.cpp @@ -239,3 +239,65 @@ 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"}); +}