Index: include/clang/Basic/SourceManager.h =================================================================== --- include/clang/Basic/SourceManager.h +++ include/clang/Basic/SourceManager.h @@ -1525,6 +1525,28 @@ /// first inclusion. FileID translateFile(const FileEntry *SourceFile) const; + /// Looks through all the local and imported source locations to find the set + /// of FileIDs that correspond to the given entry. + /// + /// When the given FileEntry is different to the entry of a file with the same + /// filepath, this function will stat the filepath to check if the entry + /// changed because of an on-disk update. + /// + /// \returns the set of FileIDs for the given file, in the order of inclusion. + llvm::SmallVector + findFileIDsForFile(const FileEntry *SourceFile) const; + +private: + /// Looks through all the local and imported source locations to find the set + /// of FileIDs that correspond to the given entry. + /// + /// \param Callback should return true to exit the search. + /// + /// \returns true if the callback returned true, false otherwise. + bool findFileIDsForFile(const FileEntry *SourceFile, + llvm::function_ref Callback) const; + +public: /// Get the source location in \p FID for the given line:col. /// Returns null location if \p FID is not a file SLocEntry. SourceLocation translateLineCol(FileID FID, Index: lib/Basic/SourceManager.cpp =================================================================== --- lib/Basic/SourceManager.cpp +++ lib/Basic/SourceManager.cpp @@ -1602,6 +1602,52 @@ return translateLineCol(FirstFID, Line, Col); } +bool SourceManager::findFileIDsForFile( + const FileEntry *SourceFile, + llvm::function_ref Callback) const { + assert(SourceFile && "Null source file!"); + + // Look through all of the local source locations. + for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) { + bool Invalid = false; + const SLocEntry &SLoc = getLocalSLocEntry(I, &Invalid); + if (Invalid) + return false; + if (!SLoc.isFile()) + continue; + const ContentCache *FileContentCache = SLoc.getFile().getContentCache(); + if (!FileContentCache || !FileContentCache->OrigEntry) + continue; + + if (FileContentCache->OrigEntry == SourceFile) { + if (Callback(FileID::get(I))) + return true; + } + } + + // If that still didn't help, try the modules. + for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) { + const SLocEntry &SLoc = getLoadedSLocEntry(I); + if (SLoc.isFile() && SLoc.getFile().getContentCache() && + SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { + if (Callback(FileID::get(-int(I) - 2))) + return true; + } + } + + return false; +} + +llvm::SmallVector +SourceManager::findFileIDsForFile(const FileEntry *SourceFile) const { + llvm::SmallVector Result; + findFileIDsForFile(SourceFile, [&](FileID F) { + Result.push_back(F); + return false; + }); + return Result; +} + /// Get the FileID for the given file. /// /// If the source file is included multiple times, the FileID will be the @@ -1650,72 +1696,17 @@ } } - if (FirstFID.isInvalid()) { - // The location we're looking for isn't in the main file; look - // through all of the local source locations. - for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) { - bool Invalid = false; - const SLocEntry &SLoc = getLocalSLocEntry(I, &Invalid); - if (Invalid) - return FileID(); - - if (SLoc.isFile() && - SLoc.getFile().getContentCache() && - SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { - FirstFID = FileID::get(I); - break; - } - } - // If that still didn't help, try the modules. - if (FirstFID.isInvalid()) { - for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) { - const SLocEntry &SLoc = getLoadedSLocEntry(I); - if (SLoc.isFile() && - SLoc.getFile().getContentCache() && - SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { - FirstFID = FileID::get(-int(I) - 2); - break; - } - } - } - } + if (FirstFID.isValid()) + return FirstFID; - // If we haven't found what we want yet, try again, but this time stat() - // each of the files in case the files have changed since we originally - // parsed the file. - if (FirstFID.isInvalid() && - (SourceFileName || - (SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) && - (SourceFileUID || (SourceFileUID = getActualFileUID(SourceFile)))) { - bool Invalid = false; - for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) { - FileID IFileID; - IFileID.ID = I; - const SLocEntry &SLoc = getSLocEntry(IFileID, &Invalid); - if (Invalid) - return FileID(); - - if (SLoc.isFile()) { - const ContentCache *FileContentCache - = SLoc.getFile().getContentCache(); - const FileEntry *Entry = FileContentCache ? FileContentCache->OrigEntry - : nullptr; - if (Entry && - *SourceFileName == llvm::sys::path::filename(Entry->getName())) { - if (Optional EntryUID = - getActualFileUID(Entry)) { - if (*SourceFileUID == *EntryUID) { - FirstFID = FileID::get(I); - SourceFile = Entry; - break; - } - } - } - } - } - } + // The location we're looking for isn't in the main file; look + // through all of the local and the imported source locations. + if (findFileIDsForFile(SourceFile, [&](FileID F) { + FirstFID = F; + return true; + })) + return FirstFID; - (void) SourceFile; return FirstFID; } Index: unittests/Basic/SourceManagerTest.cpp =================================================================== --- unittests/Basic/SourceManagerTest.cpp +++ unittests/Basic/SourceManagerTest.cpp @@ -425,6 +425,60 @@ EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc)); } +TEST_F(SourceManagerTest, findFileIDsForFile) { + const char *header = "int x;"; + + const char *main = "#include \n" + "#include \n"; + + std::unique_ptr HeaderBuf = + llvm::MemoryBuffer::getMemBuffer(header); + std::unique_ptr MainBuf = + llvm::MemoryBuffer::getMemBuffer(main); + + const FileEntry *HeaderFile = + FileMgr.getVirtualFile("/test-header.h", HeaderBuf->getBufferSize(), 0); + SourceMgr.overrideFileContents(HeaderFile, std::move(HeaderBuf)); + const FileEntry *MainFile = + FileMgr.getVirtualFile("main.cpp", MainBuf->getBufferSize(), 0); + SourceMgr.overrideFileContents(MainFile, std::move(MainBuf)); + SourceMgr.setMainFileID( + SourceMgr.createFileID(MainFile, SourceLocation(), SrcMgr::C_User)); + + TrivialModuleLoader ModLoader; + MemoryBufferCache PCMCache; + HeaderSearch HeaderInfo(std::make_shared(), SourceMgr, + Diags, LangOpts, &*Target); + Preprocessor PP(std::make_shared(), Diags, LangOpts, + SourceMgr, PCMCache, HeaderInfo, ModLoader, + /*IILookup =*/nullptr, + /*OwnsHeaderSearch =*/false); + PP.Initialize(*Target); + + PP.EnterMainSourceFile(); + + while (1) { + Token tok; + PP.Lex(tok); + if (tok.is(tok::eof)) + break; + } + + llvm::SmallVector MainFileID = + SourceMgr.findFileIDsForFile(MainFile); + ASSERT_EQ(1U, MainFileID.size()); + ASSERT_EQ(MainFileID[0], SourceMgr.getMainFileID()); + + llvm::SmallVector Files = SourceMgr.findFileIDsForFile(HeaderFile); + + ASSERT_EQ(2U, Files.size()); + ASSERT_NE(Files[0], Files[1]); + SourceLocation Loc1 = SourceMgr.translateLineCol(Files[0], 1, 1); + SourceLocation Loc2 = SourceMgr.translateLineCol(Files[1], 1, 1); + ASSERT_NE(Loc1, Loc2); + ASSERT_TRUE(SourceMgr.isBeforeInTranslationUnit(Loc1, Loc2)); +} + #endif } // anonymous namespace