arphaman created this revision. arphaman added reviewers: rsmith, bruno, Bigcheese, jkorous, harlanhaskins. Herald added subscribers: dexonsmith, mgorny. Herald added a project: clang.
This patch introduces a parallel API to FileManager's `getFile`: `getFileEntryRef`, which returns a reference to the `FileEntry`, and the name that was used to access the file. The new API is adopted only in the HeaderSearch and Preprocessor for include file lookup, so that the accessed path can be propagated to SourceManager's `FileInfo`. SourceManager's `FileInfo` now can report this accessed path, using the new `getName` method. This API is then adopted in the dependency collector, which now correctly reports dependencies when a file is included both using a symlink and a real path in the case when the FileManager is reused across multiple Preprocessor invocations. Note that this patch does not fix all dependency collector issues, as the same problem is still present in other cases when dependencies are obtained using `FileSkipped`, `InclusionDirective`, and `HasInclude`. This will be fixed in a follow-up patch. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D65907 Files: clang/include/clang/Basic/FileManager.h clang/include/clang/Basic/SourceManager.h clang/include/clang/Lex/DirectoryLookup.h clang/include/clang/Lex/HeaderSearch.h clang/include/clang/Lex/Preprocessor.h clang/lib/Basic/FileManager.cpp clang/lib/Basic/SourceManager.cpp clang/lib/Frontend/CompilerInstance.cpp clang/lib/Frontend/DependencyFile.cpp clang/lib/Frontend/FrontendActions.cpp clang/lib/Frontend/Rewrite/InclusionRewriter.cpp clang/lib/Frontend/VerifyDiagnosticConsumer.cpp clang/lib/Lex/HeaderSearch.cpp clang/lib/Lex/PPDirectives.cpp clang/lib/Lex/PPMacroExpansion.cpp clang/lib/Lex/Pragma.cpp clang/lib/Lex/Preprocessor.cpp clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/unittests/Tooling/CMakeLists.txt clang/unittests/Tooling/DependencyScannerTest.cpp
Index: clang/unittests/Tooling/DependencyScannerTest.cpp =================================================================== --- /dev/null +++ clang/unittests/Tooling/DependencyScannerTest.cpp @@ -0,0 +1,118 @@ +//===- 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/Tooling.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" +#include <algorithm> +#include <string> + +namespace clang { +namespace tooling { + +namespace { + +/// Prints out all of the gathered dependencies into a string. +class TestFileCollector : public DependencyFileGenerator { +public: + TestFileCollector(DependencyOutputOptions &Opts, + std::vector<std::string> &Deps) + : DependencyFileGenerator(Opts), Deps(Deps) {} + + void finishedMainFile(DiagnosticsEngine &Diags) override { + Deps = getDependencies(); + } + +private: + std::vector<std::string> &Deps; +}; + +class TestDependencyScanningAction : public tooling::ToolAction { +public: + TestDependencyScanningAction(std::vector<std::string> &Deps) : Deps(Deps) {} + + bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, + FileManager *FileMgr, + std::shared_ptr<PCHContainerOperations> 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<TestFileCollector>( + Compiler.getInvocation().getDependencyOutputOpts(), Deps)); + + auto Action = llvm::make_unique<PreprocessOnlyAction>(); + return Compiler.ExecuteAction(*Action); + } + +private: + std::vector<std::string> &Deps; +}; + +} // namespace + +TEST(DependencyScanner, ScanDepsReuseFilemanager) { + std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"}; + StringRef CWD = "/root"; + FixedCompilationDatabase CDB(CWD, Compilation); + + auto VFS = new llvm::vfs::InMemoryFileSystem(); + VFS->setCurrentWorkingDirectory(CWD); + VFS->addFile("/root/header.h", 0, llvm::MemoryBuffer::getMemBuffer("\n")); + VFS->addHardLink("/root/symlink.h", "/root/header.h"); + VFS->addFile("/root/test.cpp", 0, + llvm::MemoryBuffer::getMemBuffer( + "#include \"symlink.h\"\n#include \"header.h\"\n")); + + ClangTool Tool(CDB, {"test.cpp"}, std::make_shared<PCHContainerOperations>(), + VFS); + Tool.clearArgumentsAdjusters(); + std::vector<std::string> Deps; + TestDependencyScanningAction Action(Deps); + Tool.run(&Action); + // The first invocation should return dependencies in order of access. + ASSERT_EQ(Deps.size(), 3u); + EXPECT_EQ(Deps[0], "/root/test.cpp"); + EXPECT_EQ(Deps[1], "/root/symlink.h"); + EXPECT_EQ(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(Deps[0], "/root/test.cpp"); + EXPECT_EQ(Deps[1], "/root/symlink.h"); + EXPECT_EQ(Deps[2], "/root/header.h"); + + EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u); +} + +} // end namespace tooling +} // end namespace clang Index: clang/unittests/Tooling/CMakeLists.txt =================================================================== --- clang/unittests/Tooling/CMakeLists.txt +++ clang/unittests/Tooling/CMakeLists.txt @@ -15,6 +15,7 @@ CastExprTest.cpp CommentHandlerTest.cpp CompilationDatabaseTest.cpp + DependencyScannerTest.cpp DiagnosticsYamlTest.cpp ExecutionTest.cpp FixItTest.cpp Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -1842,6 +1842,7 @@ Entry.IsTransient, Entry.IsTopLevelModuleMap}; + // FIXME: The path should be taken from the FileEntryRef. EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName()); } Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -1514,6 +1514,7 @@ } SrcMgr::CharacteristicKind FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; + // FIXME: The FileID should be created from the FileEntryRef. FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter, ID, BaseOffset + Record[0]); SrcMgr::FileInfo &FileInfo = Index: clang/lib/Lex/Preprocessor.cpp =================================================================== --- clang/lib/Lex/Preprocessor.cpp +++ clang/lib/Lex/Preprocessor.cpp @@ -563,7 +563,7 @@ // Lookup and save the FileID for the through header. If it isn't found // in the search path, it's a fatal error. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile( + Optional<FileEntryRef> File = LookupFile( SourceLocation(), PPOpts->PCHThroughHeader, /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, CurDir, /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, @@ -575,7 +575,7 @@ return; } setPCHThroughHeaderFileID( - SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User)); + SourceMgr.createFileID(*File, SourceLocation(), SrcMgr::C_User)); } // Skip tokens from the Predefines and if needed the main file. Index: clang/lib/Lex/Pragma.cpp =================================================================== --- clang/lib/Lex/Pragma.cpp +++ clang/lib/Lex/Pragma.cpp @@ -498,7 +498,7 @@ // Search include directories for this file. const DirectoryLookup *CurDir; - const FileEntry *File = + Optional<FileEntryRef> File = LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr, nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr); if (!File) { Index: clang/lib/Lex/PPMacroExpansion.cpp =================================================================== --- clang/lib/Lex/PPMacroExpansion.cpp +++ clang/lib/Lex/PPMacroExpansion.cpp @@ -1210,19 +1210,21 @@ // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = + Optional<FileEntryRef> File = PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr); if (PPCallbacks *Callbacks = PP.getPPCallbacks()) { SrcMgr::CharacteristicKind FileType = SrcMgr::C_User; if (File) - FileType = PP.getHeaderSearchInfo().getFileDirFlavor(File); - Callbacks->HasInclude(FilenameLoc, Filename, isAngled, File, FileType); + FileType = + PP.getHeaderSearchInfo().getFileDirFlavor(&File->getFileEntry()); + Callbacks->HasInclude(FilenameLoc, Filename, isAngled, + File ? &File->getFileEntry() : nullptr, FileType); } // Get the result value. A result of true means the file exists. - return File != nullptr; + return File.hasValue(); } /// EvaluateHasInclude - Process a '__has_include("path")' expression. Index: clang/lib/Lex/PPDirectives.cpp =================================================================== --- clang/lib/Lex/PPDirectives.cpp +++ clang/lib/Lex/PPDirectives.cpp @@ -679,7 +679,7 @@ return nullptr; } -const FileEntry *Preprocessor::LookupFile( +Optional<FileEntryRef> Preprocessor::LookupFile( SourceLocation FilenameLoc, StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const FileEntry *FromFile, const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath, @@ -740,7 +740,7 @@ // the include path until we find that file or run out of files. const DirectoryLookup *TmpCurDir = CurDir; const DirectoryLookup *TmpFromDir = nullptr; - while (const FileEntry *FE = HeaderInfo.LookupFile( + while (Optional<FileEntryRef> FE = HeaderInfo.LookupFile( Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir, Includers, SearchPath, RelativePath, RequestingModule, SuggestedModule, /*IsMapped=*/nullptr, @@ -748,7 +748,7 @@ // Keep looking as if this file did a #include_next. TmpFromDir = TmpCurDir; ++TmpFromDir; - if (FE == FromFile) { + if (&FE->getFileEntry() == FromFile) { // Found it. FromDir = TmpFromDir; CurDir = TmpCurDir; @@ -758,7 +758,7 @@ } // Do a standard file entry lookup. - const FileEntry *FE = HeaderInfo.LookupFile( + Optional<FileEntryRef> FE = HeaderInfo.LookupFile( Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath, RelativePath, RequestingModule, SuggestedModule, IsMapped, IsFrameworkFound, SkipCache, BuildSystemModule); @@ -766,7 +766,7 @@ if (SuggestedModule && !LangOpts.AsmPreprocessor) HeaderInfo.getModuleMap().diagnoseHeaderInclusion( RequestingModule, RequestingModuleIsModuleInterface, FilenameLoc, - Filename, FE); + Filename, &FE->getFileEntry()); return FE; } @@ -776,14 +776,13 @@ // headers on the #include stack and pass them to HeaderInfo. if (IsFileLexer()) { if ((CurFileEnt = CurPPLexer->getFileEntry())) { - if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt, - SearchPath, RelativePath, - RequestingModule, - SuggestedModule))) { + if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader( + Filename, CurFileEnt, SearchPath, RelativePath, RequestingModule, + SuggestedModule)) { if (SuggestedModule && !LangOpts.AsmPreprocessor) HeaderInfo.getModuleMap().diagnoseHeaderInclusion( RequestingModule, RequestingModuleIsModuleInterface, FilenameLoc, - Filename, FE); + Filename, &FE->getFileEntry()); return FE; } } @@ -792,13 +791,13 @@ for (IncludeStackInfo &ISEntry : llvm::reverse(IncludeMacroStack)) { if (IsFileLexer(ISEntry)) { if ((CurFileEnt = ISEntry.ThePPLexer->getFileEntry())) { - if ((FE = HeaderInfo.LookupSubframeworkHeader( + if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader( Filename, CurFileEnt, SearchPath, RelativePath, - RequestingModule, SuggestedModule))) { + RequestingModule, SuggestedModule)) { if (SuggestedModule && !LangOpts.AsmPreprocessor) HeaderInfo.getModuleMap().diagnoseHeaderInclusion( RequestingModule, RequestingModuleIsModuleInterface, - FilenameLoc, Filename, FE); + FilenameLoc, Filename, &FE->getFileEntry()); return FE; } } @@ -806,7 +805,7 @@ } // Otherwise, we really couldn't find the file. - return nullptr; + return None; } //===----------------------------------------------------------------------===// @@ -1754,13 +1753,16 @@ llvm::sys::path::native(NormalizedPath); #endif } - const FileEntry *File = LookupFile( - FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, - isAngled, LookupFrom, LookupFromFile, CurDir, - Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr, - &SuggestedModule, &IsMapped, &IsFrameworkFound); - if (!File) { + auto LookupHeaderFile = [&]() -> Optional<FileEntryRef> { + Optional<FileEntryRef> File = LookupFile( + FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, + isAngled, LookupFrom, LookupFromFile, CurDir, + Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr, + &SuggestedModule, &IsMapped, &IsFrameworkFound); + if (File) + return File; + if (Callbacks) { // Give the clients a chance to recover. SmallString<128> RecoveryPath; @@ -1771,103 +1773,109 @@ HeaderInfo.AddSearchPath(DL, isAngled); // Try the lookup again, skipping the cache. - File = LookupFile( + Optional<FileEntryRef> File = LookupFile( FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled, LookupFrom, LookupFromFile, CurDir, nullptr, nullptr, &SuggestedModule, &IsMapped, /*IsFrameworkFound=*/nullptr, /*SkipCache*/ true); + if (File) + return File; } } } - if (!SuppressIncludeNotFoundError) { - // If the file could not be located and it was included via angle - // brackets, we can attempt a lookup as though it were a quoted path to - // provide the user with a possible fixit. - if (isAngled) { - File = LookupFile( - FilenameLoc, - LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false, - LookupFrom, LookupFromFile, CurDir, - Callbacks ? &SearchPath : nullptr, - Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped, - /*IsFrameworkFound=*/nullptr); - if (File) { - Diag(FilenameTok, - diag::err_pp_file_not_found_angled_include_not_fatal) - << Filename << IsImportDecl - << FixItHint::CreateReplacement(FilenameRange, - "\"" + Filename.str() + "\""); - } + if (SuppressIncludeNotFoundError) + return None; + + // If the file could not be located and it was included via angle + // brackets, we can attempt a lookup as though it were a quoted path to + // provide the user with a possible fixit. + if (isAngled) { + Optional<FileEntryRef> File = LookupFile( + FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, + false, LookupFrom, LookupFromFile, CurDir, + Callbacks ? &SearchPath : nullptr, + Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped, + /*IsFrameworkFound=*/nullptr); + if (File) { + Diag(FilenameTok, diag::err_pp_file_not_found_angled_include_not_fatal) + << Filename << IsImportDecl + << FixItHint::CreateReplacement(FilenameRange, + "\"" + Filename.str() + "\""); + return File; } + } - // Check for likely typos due to leading or trailing non-isAlphanumeric - // characters - StringRef OriginalFilename = Filename; - if (LangOpts.SpellChecking && !File) { - // A heuristic to correct a typo file name by removing leading and - // trailing non-isAlphanumeric characters. - auto CorrectTypoFilename = [](llvm::StringRef Filename) { - Filename = Filename.drop_until(isAlphanumeric); - while (!Filename.empty() && !isAlphanumeric(Filename.back())) { - Filename = Filename.drop_back(); - } - return Filename; - }; - StringRef TypoCorrectionName = CorrectTypoFilename(Filename); - SmallString<128> NormalizedTypoCorrectionPath; - if (LangOpts.MSVCCompat) { - NormalizedTypoCorrectionPath = TypoCorrectionName.str(); + // Check for likely typos due to leading or trailing non-isAlphanumeric + // characters + StringRef OriginalFilename = Filename; + if (LangOpts.SpellChecking) { + // A heuristic to correct a typo file name by removing leading and + // trailing non-isAlphanumeric characters. + auto CorrectTypoFilename = [](llvm::StringRef Filename) { + Filename = Filename.drop_until(isAlphanumeric); + while (!Filename.empty() && !isAlphanumeric(Filename.back())) { + Filename = Filename.drop_back(); + } + return Filename; + }; + StringRef TypoCorrectionName = CorrectTypoFilename(Filename); + SmallString<128> NormalizedTypoCorrectionPath; + if (LangOpts.MSVCCompat) { + NormalizedTypoCorrectionPath = TypoCorrectionName.str(); #ifndef _WIN32 - llvm::sys::path::native(NormalizedTypoCorrectionPath); + llvm::sys::path::native(NormalizedTypoCorrectionPath); #endif - } - File = LookupFile( - FilenameLoc, - LangOpts.MSVCCompat ? NormalizedTypoCorrectionPath.c_str() - : TypoCorrectionName, - isAngled, LookupFrom, LookupFromFile, CurDir, - Callbacks ? &SearchPath : nullptr, - Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped, - /*IsFrameworkFound=*/nullptr); - if (File) { - auto Hint = - isAngled - ? FixItHint::CreateReplacement( - FilenameRange, "<" + TypoCorrectionName.str() + ">") - : FixItHint::CreateReplacement( - FilenameRange, "\"" + TypoCorrectionName.str() + "\""); - Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal) - << OriginalFilename << TypoCorrectionName << Hint; - // We found the file, so set the Filename to the name after typo - // correction. - Filename = TypoCorrectionName; - } } - - // If the file is still not found, just go with the vanilla diagnostic - if (!File) { - Diag(FilenameTok, diag::err_pp_file_not_found) << OriginalFilename - << FilenameRange; - if (IsFrameworkFound) { - size_t SlashPos = OriginalFilename.find('/'); - assert(SlashPos != StringRef::npos && - "Include with framework name should have '/' in the filename"); - StringRef FrameworkName = OriginalFilename.substr(0, SlashPos); - FrameworkCacheEntry &CacheEntry = - HeaderInfo.LookupFrameworkCache(FrameworkName); - assert(CacheEntry.Directory && "Found framework should be in cache"); - Diag(FilenameTok, diag::note_pp_framework_without_header) - << OriginalFilename.substr(SlashPos + 1) << FrameworkName - << CacheEntry.Directory->getName(); - } + Optional<FileEntryRef> File = LookupFile( + FilenameLoc, + LangOpts.MSVCCompat ? NormalizedTypoCorrectionPath.c_str() + : TypoCorrectionName, + isAngled, LookupFrom, LookupFromFile, CurDir, + Callbacks ? &SearchPath : nullptr, + Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped, + /*IsFrameworkFound=*/nullptr); + if (File) { + auto Hint = + isAngled + ? FixItHint::CreateReplacement( + FilenameRange, "<" + TypoCorrectionName.str() + ">") + : FixItHint::CreateReplacement( + FilenameRange, "\"" + TypoCorrectionName.str() + "\""); + Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal) + << OriginalFilename << TypoCorrectionName << Hint; + // We found the file, so set the Filename to the name after typo + // correction. + Filename = TypoCorrectionName; + return File; } } - } + + // If the file is still not found, just go with the vanilla diagnostic + assert(!File.hasValue() && "expected missing file"); + Diag(FilenameTok, diag::err_pp_file_not_found) + << OriginalFilename << FilenameRange; + if (IsFrameworkFound) { + size_t SlashPos = OriginalFilename.find('/'); + assert(SlashPos != StringRef::npos && + "Include with framework name should have '/' in the filename"); + StringRef FrameworkName = OriginalFilename.substr(0, SlashPos); + FrameworkCacheEntry &CacheEntry = + HeaderInfo.LookupFrameworkCache(FrameworkName); + assert(CacheEntry.Directory && "Found framework should be in cache"); + Diag(FilenameTok, diag::note_pp_framework_without_header) + << OriginalFilename.substr(SlashPos + 1) << FrameworkName + << CacheEntry.Directory->getName(); + } + + return None; + }; + + Optional<FileEntryRef> File = LookupHeaderFile(); if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) { - if (isPCHThroughHeader(File)) + if (File && isPCHThroughHeader(&File->getFileEntry())) SkippingUntilPCHThroughHeader = false; return {ImportAction::None}; } @@ -1878,7 +1886,8 @@ // some directives (e.g. #endif of a header guard) will never be seen. // Since this will lead to confusing errors, avoid the inclusion. if (File && PreambleConditionalStack.isRecording() && - SourceMgr.translateFile(File) == SourceMgr.getMainFileID()) { + SourceMgr.translateFile(&File->getFileEntry()) == + SourceMgr.getMainFileID()) { Diag(FilenameTok.getLocation(), diag::err_pp_including_mainfile_in_preamble); return {ImportAction::None}; @@ -1897,7 +1906,7 @@ // include cycle. Don't enter already processed files again as it can lead to // reaching the max allowed include depth again. if (Action == Enter && HasReachedMaxIncludeDepth && File && - HeaderInfo.getFileInfo(File).NumIncludes) + HeaderInfo.getFileInfo(&File->getFileEntry()).NumIncludes) Action = IncludeLimitReached; // Determine whether we should try to import the module for this #include, if @@ -1973,7 +1982,8 @@ SrcMgr::CharacteristicKind FileCharacter = SourceMgr.getFileCharacteristic(FilenameTok.getLocation()); if (File) - FileCharacter = std::max(HeaderInfo.getFileDirFlavor(File), FileCharacter); + FileCharacter = std::max(HeaderInfo.getFileDirFlavor(&File->getFileEntry()), + FileCharacter); // If this is a '#import' or an import-declaration, don't re-enter the file. // @@ -1987,8 +1997,8 @@ // Ask HeaderInfo if we should enter this #include file. If not, #including // this file will have no effect. if (Action == Enter && File && - !HeaderInfo.ShouldEnterIncludeFile(*this, File, EnterOnce, - getLangOpts().Modules, + !HeaderInfo.ShouldEnterIncludeFile(*this, &File->getFileEntry(), + EnterOnce, getLangOpts().Modules, SuggestedModule.getModule())) { // Even if we've already preprocessed this header once and know that we // don't need to see its contents again, we still need to import it if it's @@ -2006,11 +2016,11 @@ Callbacks->InclusionDirective( HashLoc, IncludeTok, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled, - FilenameRange, File, SearchPath, RelativePath, + FilenameRange, &File->getFileEntry(), SearchPath, RelativePath, Action == Import ? SuggestedModule.getModule() : nullptr, FileCharacter); if (Action == Skip) - Callbacks->FileSkipped(*File, FilenameTok, FileCharacter); + Callbacks->FileSkipped(File->getFileEntry(), FilenameTok, FileCharacter); } if (!File) @@ -2027,11 +2037,11 @@ // Issue a diagnostic if the name of the file on disk has a different case // than the one we're about to open. const bool CheckIncludePathPortability = - !IsMapped && File && !File->tryGetRealPathName().empty(); + !IsMapped && !File->getFileEntry().tryGetRealPathName().empty(); if (CheckIncludePathPortability) { StringRef Name = LangOpts.MSVCCompat ? NormalizedPath.str() : Filename; - StringRef RealPathName = File->tryGetRealPathName(); + StringRef RealPathName = File->getFileEntry().tryGetRealPathName(); SmallVector<StringRef, 16> Components(llvm::sys::path::begin(Name), llvm::sys::path::end(Name)); @@ -2102,7 +2112,7 @@ // position on the file where it will be included and after the expansions. if (IncludePos.isMacroID()) IncludePos = SourceMgr.getExpansionRange(IncludePos).getEnd(); - FileID FID = SourceMgr.createFileID(File, IncludePos, FileCharacter); + FileID FID = SourceMgr.createFileID(*File, IncludePos, FileCharacter); assert(FID.isValid() && "Expected valid file ID"); // If all is good, enter the new file! Index: clang/lib/Lex/HeaderSearch.cpp =================================================================== --- clang/lib/Lex/HeaderSearch.cpp +++ clang/lib/Lex/HeaderSearch.cpp @@ -303,39 +303,33 @@ return getHeaderMap()->getFileName(); } -const FileEntry *HeaderSearch::getFileAndSuggestModule( +Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule( StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir, bool IsSystemHeaderDir, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) { // If we have a module map that might map this header, load it and // check whether we'll have a suggestion for a module. - auto File = getFileMgr().getFile(FileName, /*OpenFile=*/true); + auto File = getFileMgr().getFileRef(FileName, /*OpenFile=*/true); if (!File) - return nullptr; + return None; // If there is a module that corresponds to this header, suggest it. - if (!findUsableModuleForHeader(*File, Dir ? Dir : (*File)->getDir(), - RequestingModule, SuggestedModule, - IsSystemHeaderDir)) - return nullptr; + if (!findUsableModuleForHeader( + &File->getFileEntry(), Dir ? Dir : File->getFileEntry().getDir(), + RequestingModule, SuggestedModule, IsSystemHeaderDir)) + return None; return *File; } /// LookupFile - Lookup the specified file in this search path, returning it /// if it exists or returning null if not. -const FileEntry *DirectoryLookup::LookupFile( - StringRef &Filename, - HeaderSearch &HS, - SourceLocation IncludeLoc, - SmallVectorImpl<char> *SearchPath, - SmallVectorImpl<char> *RelativePath, - Module *RequestingModule, - ModuleMap::KnownHeader *SuggestedModule, - bool &InUserSpecifiedSystemFramework, - bool &IsFrameworkFound, - bool &HasBeenMapped, - SmallVectorImpl<char> &MappedName) const { +Optional<FileEntryRef> DirectoryLookup::LookupFile( + StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc, + SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, + Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, + bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound, + bool &HasBeenMapped, SmallVectorImpl<char> &MappedName) const { InUserSpecifiedSystemFramework = false; HasBeenMapped = false; @@ -369,9 +363,19 @@ SmallString<1024> Path; StringRef Dest = HM->lookupFilename(Filename, Path); if (Dest.empty()) - return nullptr; + return None; - const FileEntry *Result; + auto FixupSearchPath = [&]() { + if (SearchPath) { + StringRef SearchPathRef(getName()); + SearchPath->clear(); + SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); + } + if (RelativePath) { + RelativePath->clear(); + RelativePath->append(Filename.begin(), Filename.end()); + } + }; // Check if the headermap maps the filename to a framework include // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the @@ -381,25 +385,14 @@ MappedName.append(Dest.begin(), Dest.end()); Filename = StringRef(MappedName.begin(), MappedName.size()); HasBeenMapped = true; - Result = HM->LookupFile(Filename, HS.getFileMgr()); - } else if (auto Res = HS.getFileMgr().getFile(Dest)) { - Result = *Res; - } else { - Result = nullptr; + // FIXME ULTRA: auto Result = HM->LookupFile(Filename, HS.getFileMgr()); + // FixupSearchPath(); + } else if (auto Res = HS.getFileMgr().getFileRef(Dest)) { + FixupSearchPath(); + return *Res; } - if (Result) { - if (SearchPath) { - StringRef SearchPathRef(getName()); - SearchPath->clear(); - SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); - } - if (RelativePath) { - RelativePath->clear(); - RelativePath->append(Filename.begin(), Filename.end()); - } - } - return Result; + return None; } /// Given a framework directory, find the top-most framework directory. @@ -464,7 +457,7 @@ /// DoFrameworkLookup - Do a lookup of the specified file in the current /// DirectoryLookup, which is a framework directory. -const FileEntry *DirectoryLookup::DoFrameworkLookup( +Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup( StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, @@ -473,7 +466,8 @@ // Framework names must have a '/' in the filename. size_t SlashPos = Filename.find('/'); - if (SlashPos == StringRef::npos) return nullptr; + if (SlashPos == StringRef::npos) + return None; // Find out if this is the home for the specified framework, by checking // HeaderSearch. Possible answers are yes/no and unknown. @@ -482,7 +476,7 @@ // If it is known and in some other directory, fail. if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir()) - return nullptr; + return None; // Otherwise, construct the path to this framework dir. @@ -505,7 +499,8 @@ // If the framework dir doesn't exist, we fail. auto Dir = FileMgr.getDirectory(FrameworkName); - if (!Dir) return nullptr; + if (!Dir) + return None; // Otherwise, if it does, remember that this is the right direntry for this // framework. @@ -544,11 +539,10 @@ FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); - const FileEntry *FE = nullptr; - if (auto File = FileMgr.getFile(FrameworkName, /*OpenFile=*/!SuggestedModule)) - FE = *File; + llvm::ErrorOr<FileEntryRef> File = + FileMgr.getFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule); - if (!FE) { + if (!File) { // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h" const char *Private = "Private"; FrameworkName.insert(FrameworkName.begin()+OrigSize, Private, @@ -557,15 +551,13 @@ SearchPath->insert(SearchPath->begin()+OrigSize, Private, Private+strlen(Private)); - if (auto File = FileMgr.getFile(FrameworkName, - /*OpenFile=*/!SuggestedModule)) - FE = *File; + File = FileMgr.getFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule); } // If we found the header and are allowed to suggest a module, do so now. - if (FE && needModuleLookup(RequestingModule, SuggestedModule)) { + if (File && needModuleLookup(RequestingModule, SuggestedModule)) { // Find the framework in which this header occurs. - StringRef FrameworkPath = FE->getDir()->getName(); + StringRef FrameworkPath = File->getFileEntry().getDir()->getName(); bool FoundFramework = false; do { // Determine whether this directory exists. @@ -589,15 +581,19 @@ bool IsSystem = getDirCharacteristic() != SrcMgr::C_User; if (FoundFramework) { if (!HS.findUsableModuleForFrameworkHeader( - FE, FrameworkPath, RequestingModule, SuggestedModule, IsSystem)) - return nullptr; + &File->getFileEntry(), FrameworkPath, RequestingModule, + SuggestedModule, IsSystem)) + return None; } else { - if (!HS.findUsableModuleForHeader(FE, getDir(), RequestingModule, - SuggestedModule, IsSystem)) - return nullptr; + if (!HS.findUsableModuleForHeader(&File->getFileEntry(), getDir(), + RequestingModule, SuggestedModule, + IsSystem)) + return None; } } - return FE; + if (File) + return *File; + return None; } void HeaderSearch::setTarget(const TargetInfo &Target) { @@ -702,7 +698,7 @@ /// for system \#include's or not (i.e. using <> instead of ""). Includers, if /// non-empty, indicates where the \#including file(s) are, in case a relative /// search is needed. Microsoft mode will pass all \#including files. -const FileEntry *HeaderSearch::LookupFile( +Optional<FileEntryRef> HeaderSearch::LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers, @@ -724,7 +720,8 @@ CurDir = nullptr; // If this was an #include_next "/absolute/file", fail. - if (FromDir) return nullptr; + if (FromDir) + return None; if (SearchPath) SearchPath->clear(); @@ -739,8 +736,9 @@ } // This is the header that MSVC's header search would have found. - const FileEntry *MSFE = nullptr; ModuleMap::KnownHeader MSSuggestedModule; + const FileEntry *MSFE_FE = nullptr; + StringRef MSFE_Name; // Unless disabled, check to see if the file is in the #includer's // directory. This cannot be based on CurDir, because each includer could be @@ -769,7 +767,7 @@ bool IncluderIsSystemHeader = Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User : BuildSystemModule; - if (const FileEntry *FE = getFileAndSuggestModule( + if (Optional<FileEntryRef> FE = getFileAndSuggestModule( TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader, RequestingModule, SuggestedModule)) { if (!Includer) { @@ -788,7 +786,7 @@ bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader; StringRef Framework = FromHFI.Framework; - HeaderFileInfo &ToHFI = getFileInfo(FE); + HeaderFileInfo &ToHFI = getFileInfo(&FE->getFileEntry()); ToHFI.DirInfo = DirInfo; ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader; ToHFI.Framework = Framework; @@ -805,7 +803,7 @@ if (First) { diagnoseFrameworkInclude(Diags, IncludeLoc, IncluderAndDir.second->getName(), Filename, - FE); + &FE->getFileEntry()); return FE; } @@ -815,7 +813,8 @@ if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) { return FE; } else { - MSFE = FE; + MSFE_FE = &FE->getFileEntry(); + MSFE_Name = FE->getName(); if (SuggestedModule) { MSSuggestedModule = *SuggestedModule; *SuggestedModule = ModuleMap::KnownHeader(); @@ -827,6 +826,9 @@ } } + Optional<FileEntryRef> MSFE(MSFE_FE ? FileEntryRef(MSFE_Name, *MSFE_FE) + : Optional<FileEntryRef>()); + CurDir = nullptr; // If this is a system #include, ignore the user #include locs. @@ -868,7 +870,7 @@ bool InUserSpecifiedSystemFramework = false; bool HasBeenMapped = false; bool IsFrameworkFoundInDir = false; - const FileEntry *FE = SearchDirs[i].LookupFile( + Optional<FileEntryRef> File = SearchDirs[i].LookupFile( Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule, SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir, HasBeenMapped, MappedName); @@ -883,12 +885,13 @@ // lookups, ignore IsFrameworkFoundInDir after the first remapping and not // just for remapping in a current search directory. *IsFrameworkFound |= (IsFrameworkFoundInDir && !CacheLookup.MappedName); - if (!FE) continue; + if (!File) + continue; CurDir = &SearchDirs[i]; // This file is a system header or C++ unfriendly if the dir is. - HeaderFileInfo &HFI = getFileInfo(FE); + HeaderFileInfo &HFI = getFileInfo(&File->getFileEntry()); HFI.DirInfo = CurDir->getDirCharacteristic(); // If the directory characteristic is User but this framework was @@ -918,7 +921,8 @@ } } - if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) { + if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr, + &File->getFileEntry(), IncludeLoc)) { if (SuggestedModule) *SuggestedModule = MSSuggestedModule; return MSFE; @@ -926,13 +930,13 @@ bool FoundByHeaderMap = !IsMapped ? false : *IsMapped; if (!Includers.empty()) - diagnoseFrameworkInclude(Diags, IncludeLoc, - Includers.front().second->getName(), Filename, - FE, isAngled, FoundByHeaderMap); + diagnoseFrameworkInclude( + Diags, IncludeLoc, Includers.front().second->getName(), Filename, + &File->getFileEntry(), isAngled, FoundByHeaderMap); // Remember this location for the next lookup we do. CacheLookup.HitIdx = i; - return FE; + return File; } // If we are including a file with a quoted include "foo.h" from inside @@ -948,12 +952,14 @@ ScratchFilename += '/'; ScratchFilename += Filename; - const FileEntry *FE = LookupFile( + Optional<FileEntryRef> File = LookupFile( ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir, Includers.front(), SearchPath, RelativePath, RequestingModule, SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr); - if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) { + if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr, + File ? &File->getFileEntry() : nullptr, + IncludeLoc)) { if (SuggestedModule) *SuggestedModule = MSSuggestedModule; return MSFE; @@ -962,11 +968,12 @@ LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename]; CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx; // FIXME: SuggestedModule. - return FE; + return File; } } - if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) { + if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr, + nullptr, IncludeLoc)) { if (SuggestedModule) *SuggestedModule = MSSuggestedModule; return MSFE; @@ -974,7 +981,7 @@ // Otherwise, didn't find it. Remember we didn't find this. CacheLookup.HitIdx = SearchDirs.size(); - return nullptr; + return None; } /// LookupSubframeworkHeader - Look up a subframework for the specified @@ -982,19 +989,17 @@ /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox /// is a subframework within Carbon.framework. If so, return the FileEntry /// for the designated file, otherwise return null. -const FileEntry *HeaderSearch:: -LookupSubframeworkHeader(StringRef Filename, - const FileEntry *ContextFileEnt, - SmallVectorImpl<char> *SearchPath, - SmallVectorImpl<char> *RelativePath, - Module *RequestingModule, - ModuleMap::KnownHeader *SuggestedModule) { +Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader( + StringRef Filename, const FileEntry *ContextFileEnt, + SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, + Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) { assert(ContextFileEnt && "No context file?"); // Framework names must have a '/' in the filename. Find it. // FIXME: Should we permit '\' on Windows? size_t SlashPos = Filename.find('/'); - if (SlashPos == StringRef::npos) return nullptr; + if (SlashPos == StringRef::npos) + return None; // Look up the base framework name of the ContextFileEnt. StringRef ContextName = ContextFileEnt->getName(); @@ -1005,7 +1010,7 @@ if (FrameworkPos == StringRef::npos || (ContextName[FrameworkPos + DotFrameworkLen] != '/' && ContextName[FrameworkPos + DotFrameworkLen] != '\\')) - return nullptr; + return None; SmallString<1024> FrameworkName(ContextName.data(), ContextName.data() + FrameworkPos + @@ -1025,7 +1030,7 @@ CacheLookup.first().size() == FrameworkName.size() && memcmp(CacheLookup.first().data(), &FrameworkName[0], CacheLookup.first().size()) != 0) - return nullptr; + return None; // Cache subframework. if (!CacheLookup.second.Directory) { @@ -1033,14 +1038,14 @@ // If the framework dir doesn't exist, we fail. auto Dir = FileMgr.getDirectory(FrameworkName); - if (!Dir) return nullptr; + if (!Dir) + return None; // Otherwise, if it does, remember that this is the right direntry for this // framework. CacheLookup.second.Directory = *Dir; } - const FileEntry *FE = nullptr; if (RelativePath) { RelativePath->clear(); @@ -1057,10 +1062,10 @@ } HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end()); - if (auto File = FileMgr.getFile(HeadersFilename, /*OpenFile=*/true)) - FE = *File; + llvm::ErrorOr<FileEntryRef> File = + FileMgr.getFileRef(HeadersFilename, /*OpenFile=*/true); - if (!FE) { + if (!File) { // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h" HeadersFilename = FrameworkName; HeadersFilename += "PrivateHeaders/"; @@ -1071,11 +1076,10 @@ } HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end()); - if (auto File = FileMgr.getFile(HeadersFilename, /*OpenFile=*/true)) - FE = *File; - - if (!FE) - return nullptr; + File = FileMgr.getFileRef(HeadersFilename, /*OpenFile=*/true); + + if (!File) + return None; } // This file is a system header or C++ unfriendly if the old file is. @@ -1084,14 +1088,15 @@ // getFileInfo could resize the vector and we don't want to rely on order // of evaluation. unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo; - getFileInfo(FE).DirInfo = DirInfo; + getFileInfo(&File->getFileEntry()).DirInfo = DirInfo; FrameworkName.pop_back(); // remove the trailing '/' - if (!findUsableModuleForFrameworkHeader(FE, FrameworkName, RequestingModule, - SuggestedModule, /*IsSystem*/ false)) - return nullptr; + if (!findUsableModuleForFrameworkHeader(&File->getFileEntry(), FrameworkName, + RequestingModule, SuggestedModule, + /*IsSystem*/ false)) + return None; - return FE; + return *File; } //===----------------------------------------------------------------------===// Index: clang/lib/Frontend/VerifyDiagnosticConsumer.cpp =================================================================== --- clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -528,15 +528,16 @@ // Lookup file via Preprocessor, like a #include. const DirectoryLookup *CurDir; - const FileEntry *FE = + Optional<FileEntryRef> File = PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr); - if (!FE) { + if (!File) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_file) << Filename << KindStr; continue; } + const FileEntry *FE = &File->getFileEntry(); if (SM.translateFile(FE).isInvalid()) SM.createFileID(FE, Pos, SrcMgr::C_User); Index: clang/lib/Frontend/Rewrite/InclusionRewriter.cpp =================================================================== --- clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -412,11 +412,11 @@ Includers; Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir())); // FIXME: Why don't we call PP.LookupFile here? - const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( + Optional<FileEntryRef> File = PP.getHeaderSearchInfo().LookupFile( Filename, SourceLocation(), isAngled, Lookup, CurDir, Includers, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - FileExists = File != nullptr; + FileExists = File.hasValue(); return true; } Index: clang/lib/Frontend/FrontendActions.cpp =================================================================== --- clang/lib/Frontend/FrontendActions.cpp +++ clang/lib/Frontend/FrontendActions.cpp @@ -287,15 +287,15 @@ SmallVector<Module::Header, 16> Headers; for (StringRef Name : ModuleHeaders) { const DirectoryLookup *CurDir = nullptr; - const FileEntry *FE = HS.LookupFile( - Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, - None, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + Optional<FileEntryRef> FE = HS.LookupFile( + Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, None, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (!FE) { CI.getDiagnostics().Report(diag::err_module_header_file_not_found) << Name; continue; } - Headers.push_back({Name, FE}); + Headers.push_back({Name, &FE->getFileEntry()}); } HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers); Index: clang/lib/Frontend/DependencyFile.cpp =================================================================== --- clang/lib/Frontend/DependencyFile.cpp +++ clang/lib/Frontend/DependencyFile.cpp @@ -46,13 +46,13 @@ // Dependency generation really does want to go all the way to the // file entry for a source location to find out what is depended on. // We do not want #line markers to affect dependency generation! - const FileEntry *FE = - SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc))); - if (!FE) + Optional<FileEntryRef> File = + SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc))); + if (!File) return; StringRef Filename = - llvm::sys::path::remove_leading_dotslash(FE->getName()); + llvm::sys::path::remove_leading_dotslash(File->getName()); DepCollector.maybeAddDependency(Filename, /*FromModule*/false, isSystem(FileType), Index: clang/lib/Frontend/CompilerInstance.cpp =================================================================== --- clang/lib/Frontend/CompilerInstance.cpp +++ clang/lib/Frontend/CompilerInstance.cpp @@ -831,33 +831,37 @@ // Figure out where to get and map in the main file. if (InputFile != "-") { - auto FileOrErr = FileMgr.getFile(InputFile, /*OpenFile=*/true); + auto FileOrErr = FileMgr.getFileRef(InputFile, /*OpenFile=*/true); if (!FileOrErr) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } - auto File = *FileOrErr; + FileEntryRef File = *FileOrErr; // The natural SourceManager infrastructure can't currently handle named // pipes, but we would at least like to accept them for the main // file. Detect them here, read them with the volatile flag so FileMgr will // pick up the correct size, and simply override their contents as we do for // STDIN. - if (File->isNamedPipe()) { - auto MB = FileMgr.getBufferForFile(File, /*isVolatile=*/true); + if (File.getFileEntry().isNamedPipe()) { + auto MB = + FileMgr.getBufferForFile(&File.getFileEntry(), /*isVolatile=*/true); if (MB) { // Create a new virtual file that will have the correct size. - File = FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0); - SourceMgr.overrideFileContents(File, std::move(*MB)); + const FileEntry *FE = + FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0); + SourceMgr.overrideFileContents(FE, std::move(*MB)); + SourceMgr.setMainFileID( + SourceMgr.createFileID(FE, SourceLocation(), Kind)); } else { Diags.Report(diag::err_cannot_open_file) << InputFile << MB.getError().message(); return false; } + } else { + SourceMgr.setMainFileID( + SourceMgr.createFileID(File, SourceLocation(), Kind)); } - - SourceMgr.setMainFileID( - SourceMgr.createFileID(File, SourceLocation(), Kind)); } else { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> SBOrErr = llvm::MemoryBuffer::getSTDIN(); Index: clang/lib/Basic/SourceManager.cpp =================================================================== --- clang/lib/Basic/SourceManager.cpp +++ clang/lib/Basic/SourceManager.cpp @@ -466,10 +466,9 @@ // If the file of the SLocEntry changed we could still have loaded it. if (!SLocEntryLoaded[Index]) { // Try to recover; create a SLocEntry so the rest of clang can handle it. - LoadedSLocEntryTable[Index] = SLocEntry::get(0, - FileInfo::get(SourceLocation(), - getFakeContentCacheForRecovery(), - SrcMgr::C_User)); + LoadedSLocEntryTable[Index] = SLocEntry::get( + 0, FileInfo::get(SourceLocation(), getFakeContentCacheForRecovery(), + SrcMgr::C_User, "")); } } @@ -556,7 +555,7 @@ /// createFileID - Create a new FileID for the specified ContentCache and /// include position. This works regardless of whether the ContentCache /// corresponds to a file or some other input source. -FileID SourceManager::createFileID(const ContentCache *File, +FileID SourceManager::createFileID(const ContentCache *File, StringRef Filename, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID, unsigned LoadedOffset) { @@ -565,14 +564,14 @@ unsigned Index = unsigned(-LoadedID) - 2; assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); assert(!SLocEntryLoaded[Index] && "FileID already loaded"); - LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, - FileInfo::get(IncludePos, File, FileCharacter)); + LoadedSLocEntryTable[Index] = SLocEntry::get( + LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename)); SLocEntryLoaded[Index] = true; return FileID::get(LoadedID); } - LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, - FileInfo::get(IncludePos, File, - FileCharacter))); + LocalSLocEntryTable.push_back( + SLocEntry::get(NextLocalOffset, + FileInfo::get(IncludePos, File, FileCharacter, Filename))); unsigned FileSize = File->getSize(); assert(NextLocalOffset + FileSize + 1 > NextLocalOffset && NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset && Index: clang/lib/Basic/FileManager.cpp =================================================================== --- clang/lib/Basic/FileManager.cpp +++ clang/lib/Basic/FileManager.cpp @@ -184,13 +184,29 @@ llvm::ErrorOr<const FileEntry *> FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) { + auto Result = getFileRef(Filename, openFile, CacheFailure); + if (Result) + return &Result->getFileEntry(); + return Result.getError(); +} + +static llvm::ErrorOr<FileEntryRef> +promoteFileRef(StringRef name, llvm::ErrorOr<FileEntry &> value) { + if (value) + return FileEntryRef(name, *value); + return value.getError(); +} + +llvm::ErrorOr<FileEntryRef> +FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { ++NumFileLookups; // See if there is already an entry in the map. auto SeenFileInsertResult = SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory}); if (!SeenFileInsertResult.second) - return promoteInnerReference(SeenFileInsertResult.first->second); + return promoteFileRef(SeenFileInsertResult.first->first(), + SeenFileInsertResult.first->second); // We've not seen this before. Fill it in. ++NumFileCacheMisses; @@ -269,9 +285,11 @@ // to switch towards a design where we return a FileName object that // encapsulates both the name by which the file was accessed and the // corresponding FileEntry. + // FIXME: The Name should be removed from FileEntry once all clients + // adopt FileEntryRef. UFE.Name = InterndFileName; - return &UFE; + return FileEntryRef(InterndFileName, UFE); } // Otherwise, we don't have this file yet, add it. @@ -292,7 +310,7 @@ // We should still fill the path even if we aren't opening the file. fillRealPathName(&UFE, InterndFileName); } - return &UFE; + return FileEntryRef(InterndFileName, UFE); } const FileEntry * Index: clang/include/clang/Lex/Preprocessor.h =================================================================== --- clang/include/clang/Lex/Preprocessor.h +++ clang/include/clang/Lex/Preprocessor.h @@ -1949,17 +1949,15 @@ /// Given a "foo" or \<foo> reference, look up the indicated file. /// - /// Returns null on failure. \p isAngled indicates whether the file + /// Returns None on failure. \p isAngled indicates whether the file /// reference is for system \#include's or not (i.e. using <> instead of ""). - const FileEntry *LookupFile(SourceLocation FilenameLoc, StringRef Filename, - bool isAngled, const DirectoryLookup *FromDir, - const FileEntry *FromFile, - const DirectoryLookup *&CurDir, - SmallVectorImpl<char> *SearchPath, - SmallVectorImpl<char> *RelativePath, - ModuleMap::KnownHeader *SuggestedModule, - bool *IsMapped, bool *IsFrameworkFound, - bool SkipCache = false); + Optional<FileEntryRef> + LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, + const DirectoryLookup *FromDir, const FileEntry *FromFile, + const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, + bool *IsFrameworkFound, bool SkipCache = false); /// Get the DirectoryLookup structure used to find the current /// FileEntry, if CurLexer is non-null and if applicable. Index: clang/include/clang/Lex/HeaderSearch.h =================================================================== --- clang/include/clang/Lex/HeaderSearch.h +++ clang/include/clang/Lex/HeaderSearch.h @@ -395,7 +395,7 @@ /// found in any of searched SearchDirs. Will be set to false if a framework /// is found only through header maps. Doesn't guarantee the requested file is /// found. - const FileEntry *LookupFile( + Optional<FileEntryRef> LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers, @@ -410,7 +410,7 @@ /// within ".../Carbon.framework/Headers/Carbon.h", check to see if /// HIToolbox is a subframework within Carbon.framework. If so, return /// the FileEntry for the designated file, otherwise return null. - const FileEntry *LookupSubframeworkHeader( + Optional<FileEntryRef> LookupSubframeworkHeader( StringRef Filename, const FileEntry *ContextFileEnt, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule); @@ -649,7 +649,7 @@ /// Look up the file with the specified name and determine its owning /// module. - const FileEntry * + Optional<FileEntryRef> getFileAndSuggestModule(StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir, bool IsSystemHeaderDir, Module *RequestingModule, Index: clang/include/clang/Lex/DirectoryLookup.h =================================================================== --- clang/include/clang/Lex/DirectoryLookup.h +++ clang/include/clang/Lex/DirectoryLookup.h @@ -176,27 +176,20 @@ /// \param [out] MappedName if this is a headermap which maps the filename to /// a framework include ("Foo.h" -> "Foo/Foo.h"), set the new name to this /// vector and point Filename to it. - const FileEntry *LookupFile(StringRef &Filename, HeaderSearch &HS, - SourceLocation IncludeLoc, - SmallVectorImpl<char> *SearchPath, - SmallVectorImpl<char> *RelativePath, - Module *RequestingModule, - ModuleMap::KnownHeader *SuggestedModule, - bool &InUserSpecifiedSystemFramework, - bool &IsFrameworkFound, - bool &HasBeenMapped, - SmallVectorImpl<char> &MappedName) const; + Optional<FileEntryRef> + LookupFile(StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, Module *RequestingModule, + ModuleMap::KnownHeader *SuggestedModule, + bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound, + bool &HasBeenMapped, SmallVectorImpl<char> &MappedName) const; private: - const FileEntry *DoFrameworkLookup( - StringRef Filename, HeaderSearch &HS, - SmallVectorImpl<char> *SearchPath, - SmallVectorImpl<char> *RelativePath, - Module *RequestingModule, + Optional<FileEntryRef> DoFrameworkLookup( + StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, - bool &InUserSpecifiedSystemFramework, - bool &IsFrameworkFound) const; - + bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound) const; }; } // end namespace clang Index: clang/include/clang/Basic/SourceManager.h =================================================================== --- clang/include/clang/Basic/SourceManager.h +++ clang/include/clang/Basic/SourceManager.h @@ -265,16 +265,21 @@ llvm::PointerIntPair<const ContentCache*, 3, CharacteristicKind> ContentAndKind; + /// The filename that is used to access the file entry represented by the + /// content cache. + StringRef Filename; + public: /// Return a FileInfo object. static FileInfo get(SourceLocation IL, const ContentCache *Con, - CharacteristicKind FileCharacter) { + CharacteristicKind FileCharacter, StringRef Filename) { FileInfo X; X.IncludeLoc = IL.getRawEncoding(); X.NumCreatedFIDs = 0; X.HasLineDirectives = false; X.ContentAndKind.setPointer(Con); X.ContentAndKind.setInt(FileCharacter); + X.Filename = Filename; return X; } @@ -299,6 +304,10 @@ void setHasLineDirectives() { HasLineDirectives = true; } + + /// Returns the name of the file that was used when the file was loaded from + /// the underlying file system. + StringRef getName() const { return Filename; } }; /// Each ExpansionInfo encodes the expansion location - where @@ -821,7 +830,18 @@ const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile, isSystem(FileCharacter)); assert(IR && "getOrCreateContentCache() cannot return NULL"); - return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset); + return createFileID(IR, SourceFile->getName(), IncludePos, FileCharacter, + LoadedID, LoadedOffset); + } + + FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID = 0, unsigned LoadedOffset = 0) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache( + &SourceFile.getFileEntry(), isSystem(FileCharacter)); + assert(IR && "getOrCreateContentCache() cannot return NULL"); + return createFileID(IR, SourceFile.getName(), IncludePos, FileCharacter, + LoadedID, LoadedOffset); } /// Create a new FileID that represents the specified memory buffer. @@ -832,9 +852,10 @@ SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, int LoadedID = 0, unsigned LoadedOffset = 0, SourceLocation IncludeLoc = SourceLocation()) { + StringRef Name = Buffer->getBufferIdentifier(); return createFileID( createMemBufferContentCache(Buffer.release(), /*DoNotFree*/ false), - IncludeLoc, FileCharacter, LoadedID, LoadedOffset); + Name, IncludeLoc, FileCharacter, LoadedID, LoadedOffset); } enum UnownedTag { Unowned }; @@ -847,8 +868,9 @@ SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, int LoadedID = 0, unsigned LoadedOffset = 0, SourceLocation IncludeLoc = SourceLocation()) { - return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/true), - IncludeLoc, FileCharacter, LoadedID, LoadedOffset); + return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/ true), + Buffer->getBufferIdentifier(), IncludeLoc, + FileCharacter, LoadedID, LoadedOffset); } /// Get the FileID for \p SourceFile if it exists. Otherwise, create a @@ -997,6 +1019,19 @@ return Content->OrigEntry; } + /// Returns the FileEntryRef for the provided FileID. + Optional<FileEntryRef> getFileEntryRefForID(FileID FID) const { + bool MyInvalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) + return None; + + const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache(); + if (!Content || !Content->OrigEntry) + return None; + return FileEntryRef(Entry.getFile().getName(), *Content->OrigEntry); + } + /// Returns the FileEntry record for the provided SLocEntry. const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const { @@ -1785,10 +1820,10 @@ /// /// This works regardless of whether the ContentCache corresponds to a /// file or some other input source. - FileID createFileID(const SrcMgr::ContentCache* File, + FileID createFileID(const SrcMgr::ContentCache *File, StringRef Filename, SourceLocation IncludePos, - SrcMgr::CharacteristicKind DirCharacter, - int LoadedID, unsigned LoadedOffset); + SrcMgr::CharacteristicKind DirCharacter, int LoadedID, + unsigned LoadedOffset); const SrcMgr::ContentCache * getOrCreateContentCache(const FileEntry *SourceFile, Index: clang/include/clang/Basic/FileManager.h =================================================================== --- clang/include/clang/Basic/FileManager.h +++ clang/include/clang/Basic/FileManager.h @@ -106,6 +106,34 @@ bool isOpenForTests() const { return File != nullptr; } }; +/// A reference to a \c FileEntry that includes the name of the file as it was +/// accessed by the FileManager's client. +class FileEntryRef { +public: + FileEntryRef(StringRef Name, const FileEntry &Entry) + : Name(Name), Entry(Entry) {} + + const StringRef getName() const { return Name; } + + const FileEntry &getFileEntry() const { return Entry; } + + off_t getSize() const { return Entry.getSize(); } + + unsigned getUID() const { return Entry.getUID(); } + + const llvm::sys::fs::UniqueID &getUniqueID() const { + return Entry.getUniqueID(); + } + + time_t getModificationTime() const { return Entry.getModificationTime(); } + + const DirectoryEntry *getDir() const { return Entry.getDir(); } + +private: + StringRef Name; + const FileEntry &Entry; +}; + /// Implements support for file system lookup, file system caching, /// and directory search management. /// @@ -200,6 +228,9 @@ /// Removes the FileSystemStatCache object from the manager. void clearStatCache(); + /// Returns the number of unique real file entries cached by the file manager. + size_t getNumUniqueRealFiles() const { return UniqueRealFiles.size(); } + /// Lookup, cache, and verify the specified directory (real or /// virtual). /// @@ -215,6 +246,10 @@ /// Lookup, cache, and verify the specified file (real or /// virtual). /// + /// This function is deprecated and will be removed at some point in the + /// future, new clients should use + /// \c getFileRef. + /// /// This returns a \c std::error_code if there was an error loading the file. /// If there is no error, the FileEntry is guaranteed to be non-NULL. /// @@ -225,6 +260,21 @@ llvm::ErrorOr<const FileEntry *> getFile(StringRef Filename, bool OpenFile = false, bool CacheFailure = true); + /// Lookup, cache, and verify the specified file (real or virtual). Return the + /// reference to the file entry together with the exact path that was used to + /// access a file by a particular call to getFileRef. + /// + /// This returns a \c std::error_code if there was an error loading the file, + /// or a \c FileEntryRef otherwise. + /// + /// \param OpenFile if true and the file exists, it will be opened. + /// + /// \param CacheFailure If true and the file does not exist, we'll cache + /// the failure to find this file. + llvm::ErrorOr<FileEntryRef> getFileRef(StringRef Filename, + bool OpenFile = false, + bool CacheFailure = true); + /// Returns the current file system options FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits