diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1380,7 +1380,7 @@ const auto &SM = Recorder->CCSema->getSourceManager(); llvm::StringMap ProxSources; auto MainFileID = - Includes.getID(SM.getFileEntryForID(SM.getMainFileID()), SM); + Includes.getID(SM.getFileEntryForID(SM.getMainFileID())); assert(MainFileID); for (auto &HeaderIDAndDepth : Includes.includeDepth(*MainFileID)) { auto &Source = diff --git a/clang-tools-extra/clangd/Headers.h b/clang-tools-extra/clangd/Headers.h --- a/clang-tools-extra/clangd/Headers.h +++ b/clang-tools-extra/clangd/Headers.h @@ -14,6 +14,7 @@ #include "index/Symbol.h" #include "support/Logger.h" #include "support/Path.h" +#include "clang/Basic/FileEntry.h" #include "clang/Basic/TokenKinds.h" #include "clang/Format/Format.h" #include "clang/Lex/HeaderSearch.h" @@ -119,15 +120,19 @@ RealPathNames.emplace_back(); } + void setMainFileEntry(const FileEntry *Entry) { + assert(Entry && Entry->isValid()); + assert(!RealPathNames.empty()); + this->MainFileEntry = Entry; + } + // HeaderID identifies file in the include graph. It corresponds to a // FileEntry rather than a FileID, but stays stable across preamble & main // file builds. enum class HeaderID : unsigned {}; - llvm::Optional getID(const FileEntry *Entry, - const SourceManager &SM) const; - HeaderID getOrCreateID(const FileEntry *Entry, - const SourceManager &SM); + llvm::Optional getID(const FileEntry *Entry) const; + HeaderID getOrCreateID(const FileEntry *Entry); StringRef getRealPath(HeaderID ID) const { assert(static_cast(ID) <= RealPathNames.size()); @@ -141,8 +146,8 @@ // All transitive includes (absolute paths), with their minimum include depth. // Root --> 0, #included file --> 1, etc. // Root is the ID of the header being visited first. - // Usually it is getID(SM.getFileEntryForID(SM.getMainFileID()), SM). - llvm::DenseMap includeDepth(HeaderID Root) const; + llvm::DenseMap + includeDepth(HeaderID Root = static_cast(0u)) const; // Maps HeaderID to the ids of the files included from it. llvm::DenseMap> IncludeChildren; @@ -150,16 +155,18 @@ std::vector MainFileIncludes; private: + const FileEntry *MainFileEntry; + std::vector RealPathNames; // In HeaderID order. - // HeaderID maps the FileEntry::UniqueID to the internal representation. + // FileEntry::UniqueID is mapped to the internal representation (HeaderID). // Identifying files in a way that persists from preamble build to subsequent - // builds is surprisingly hard. FileID is unavailable in - // InclusionDirective(), and RealPathName and UniqueID are not preserved in + // builds is surprisingly hard. FileID is unavailable in InclusionDirective(), + // and RealPathName and UniqueID are not preserved in // the preamble. // - // We reserve 0 to the main file and will manually check for that in getID - // and getOrCreateID because llvm::sys::fs::UniqueID is not stable when their - // content of the main file changes. + // We reserve HeaderID(0) for the main file and will manually check for that + // in getID and getOrCreateID because llvm::sys::fs::UniqueID is not stable + // when their content of the main file changes. llvm::DenseMap UIDToIndex; }; @@ -228,7 +235,7 @@ namespace llvm { -// Support Tokens as DenseMap keys. +// Support HeaderIDs as DenseMap keys. template <> struct DenseMapInfo { static inline clang::clangd::IncludeStructure::HeaderID getEmptyKey() { return static_cast( @@ -251,30 +258,6 @@ } }; -// Support Tokens as DenseMap keys. -template <> struct DenseMapInfo { - static inline llvm::sys::fs::UniqueID getEmptyKey() { - auto EmptyKey = DenseMapInfo>::getEmptyKey(); - return {EmptyKey.first, EmptyKey.second}; - } - - static inline llvm::sys::fs::UniqueID getTombstoneKey() { - auto TombstoneKey = - DenseMapInfo>::getTombstoneKey(); - return {TombstoneKey.first, TombstoneKey.second}; - } - - static unsigned getHashValue(const llvm::sys::fs::UniqueID &Tag) { - return hash_value( - std::pair(Tag.getDevice(), Tag.getFile())); - } - - static bool isEqual(const llvm::sys::fs::UniqueID &LHS, - const llvm::sys::fs::UniqueID &RHS) { - return LHS == RHS; - } -}; - } // namespace llvm #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEADERS_H diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -67,8 +67,8 @@ // Treat as if included from the main file. IncludingFileEntry = SM.getFileEntryForID(MainFID); } - auto IncludingID = Out->getOrCreateID(IncludingFileEntry, SM), - IncludedID = Out->getOrCreateID(File, SM); + auto IncludingID = Out->getOrCreateID(IncludingFileEntry), + IncludedID = Out->getOrCreateID(File); Out->IncludeChildren[IncludingID].push_back(IncludedID); } } @@ -152,14 +152,14 @@ std::unique_ptr collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out) { + Out->setMainFileEntry(SM.getFileEntryForID(SM.getMainFileID())); return std::make_unique(SM, Out); } llvm::Optional -IncludeStructure::getID(const FileEntry *Entry, - const SourceManager &SM) const { +IncludeStructure::getID(const FileEntry *Entry) const { // HeaderID of the main file is always 0; - if (SM.getMainFileID() == SM.translateFile(Entry)) { + if (Entry == MainFileEntry) { return static_cast(0u); } auto It = UIDToIndex.find(Entry->getUniqueID()); @@ -169,12 +169,11 @@ } IncludeStructure::HeaderID -IncludeStructure::getOrCreateID(const FileEntry *Entry, - const SourceManager &SM) { - // Main file's FileID was not known at IncludeStructure creation time. - if (SM.getMainFileID() == SM.translateFile(Entry)) { - UIDToIndex[Entry->getUniqueID()] = - static_cast(0u); +IncludeStructure::getOrCreateID(const FileEntry *Entry) { + // Main file's FileEntry was not known at IncludeStructure creation time. + if (Entry == MainFileEntry) { + RealPathNames[0] = MainFileEntry->tryGetRealPathName().str(); + return static_cast(0u); } auto R = UIDToIndex.try_emplace( Entry->getUniqueID(), diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp --- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp @@ -72,7 +72,7 @@ auto &SM = Clang->getSourceManager(); auto Entry = SM.getFileManager().getFile(Filename); EXPECT_TRUE(Entry); - return Includes.getOrCreateID(*Entry, SM); + return Includes.getOrCreateID(*Entry); } IncludeStructure collectIncludes() { diff --git a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp --- a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp @@ -516,10 +516,10 @@ IncludeStructure Includes = PatchedAST->getIncludeStructure(); auto MainFE = FM.getFile(testPath("foo.cpp")); ASSERT_TRUE(MainFE); - auto MainID = Includes.getID(*MainFE, SM); + auto MainID = Includes.getID(*MainFE); auto AuxFE = FM.getFile(testPath("sub/aux.h")); ASSERT_TRUE(AuxFE); - auto AuxID = Includes.getID(*AuxFE, SM); + auto AuxID = Includes.getID(*AuxFE); EXPECT_THAT(Includes.IncludeChildren[*MainID], Contains(*AuxID)); } @@ -560,12 +560,12 @@ IncludeStructure Includes = ExpectedAST.getIncludeStructure(); auto MainFE = FM.getFile(testPath("foo.cpp")); ASSERT_TRUE(MainFE); - auto MainID = Includes.getOrCreateID(*MainFE, SM); + auto MainID = Includes.getOrCreateID(*MainFE); auto &PatchedFM = PatchedAST->getSourceManager().getFileManager(); IncludeStructure PatchedIncludes = PatchedAST->getIncludeStructure(); auto PatchedMainFE = PatchedFM.getFile(testPath("foo.cpp")); ASSERT_TRUE(PatchedMainFE); - auto PatchedMainID = PatchedIncludes.getOrCreateID(*PatchedMainFE, SM); + auto PatchedMainID = PatchedIncludes.getOrCreateID(*PatchedMainFE); EXPECT_EQ(Includes.includeDepth(MainID)[MainID], PatchedIncludes.includeDepth(PatchedMainID)[PatchedMainID]); } diff --git a/llvm/include/llvm/Support/FileSystem/UniqueID.h b/llvm/include/llvm/Support/FileSystem/UniqueID.h --- a/llvm/include/llvm/Support/FileSystem/UniqueID.h +++ b/llvm/include/llvm/Support/FileSystem/UniqueID.h @@ -14,7 +14,9 @@ #ifndef LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H #define LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H +#include "llvm/ADT/DenseMap.h" #include +#include namespace llvm { namespace sys { @@ -47,6 +49,31 @@ } // end namespace fs } // end namespace sys + +// Support UniqueIDs as DenseMap keys. +template <> struct DenseMapInfo { + static inline llvm::sys::fs::UniqueID getEmptyKey() { + auto EmptyKey = DenseMapInfo>::getEmptyKey(); + return {EmptyKey.first, EmptyKey.second}; + } + + static inline llvm::sys::fs::UniqueID getTombstoneKey() { + auto TombstoneKey = + DenseMapInfo>::getTombstoneKey(); + return {TombstoneKey.first, TombstoneKey.second}; + } + + static unsigned getHashValue(const llvm::sys::fs::UniqueID &Tag) { + return hash_value( + std::pair(Tag.getDevice(), Tag.getFile())); + } + + static bool isEqual(const llvm::sys::fs::UniqueID &LHS, + const llvm::sys::fs::UniqueID &RHS) { + return LHS == RHS; + } +}; + } // end namespace llvm #endif // LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H