Index: include/clang/Basic/SourceManager.h =================================================================== --- include/clang/Basic/SourceManager.h +++ include/clang/Basic/SourceManager.h @@ -1525,6 +1525,24 @@ /// 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. + /// + /// \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,47 @@ 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() && SLoc.getFile().getContentCache() && + SLoc.getFile().getContentCache()->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,35 +1691,16 @@ } } - 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 (FirstFID.isValid()) + return FirstFID; - 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; - } - } - } - } + // 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; // 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 Index: unittests/Basic/SourceManagerTest.cpp =================================================================== --- unittests/Basic/SourceManagerTest.cpp +++ unittests/Basic/SourceManagerTest.cpp @@ -377,6 +377,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