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 @@ -62,7 +62,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Inclusion &); bool operator==(const Inclusion &LHS, const Inclusion &RHS); -// Contains information about one file in the build grpah and its direct +// Contains information about one file in the build graph and its direct // dependencies. Doesn't own the strings it references (IncludeGraph is // self-contained). struct IncludeGraphNode { @@ -112,6 +112,22 @@ // in any non-preamble inclusions. class IncludeStructure { public: + using File = unsigned; + + llvm::Optional getFile(StringRef Name) const { + auto It = NameToIndex.find(Name); + if (It == NameToIndex.end() || Name.empty()) + return llvm::None; + return It->second; + } + + llvm::ArrayRef getIncludedFiles(File Index) const { + auto It = IncludeChildren.find(Index); + if (It == IncludeChildren.end()) + return {}; + return It->second; + } + std::vector MainFileIncludes; // Return all transitively reachable files. @@ -122,24 +138,27 @@ // Root --> 0, #included file --> 1, etc. // Root is clang's name for a file, which may not be absolute. // Usually it should be SM.getFileEntryForID(SM.getMainFileID())->getName(). - llvm::StringMap includeDepth(llvm::StringRef Root) const; + llvm::StringMap includeDepth(StringRef Name) const; // This updates IncludeDepth(), but not MainFileIncludes. void recordInclude(llvm::StringRef IncludingName, llvm::StringRef IncludedName, llvm::StringRef IncludedRealName); + using AbstractIncludeGraph = llvm::DenseMap>; + private: + File getOrCreatefileIndex(llvm::StringRef Name); + // 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 the preamble. // We use the FileEntry::Name, which is stable, interned into a "file index". // The paths we want to expose are the RealPathName, so store those too. std::vector RealPathNames; // In file index order. - unsigned fileIndex(llvm::StringRef Name); - llvm::StringMap NameToIndex; // Values are file indexes. + llvm::StringMap NameToIndex; // Values are file indexes. // Maps a file's index to that of the files it includes. - llvm::DenseMap> IncludeChildren; + AbstractIncludeGraph IncludeChildren; }; /// Returns a PPCallback that visits all inclusions in the main file. 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 @@ -157,31 +157,33 @@ void IncludeStructure::recordInclude(llvm::StringRef IncludingName, llvm::StringRef IncludedName, llvm::StringRef IncludedRealName) { - auto Child = fileIndex(IncludedName); + auto Child = getOrCreatefileIndex(IncludedName); if (!IncludedRealName.empty() && RealPathNames[Child].empty()) RealPathNames[Child] = std::string(IncludedRealName); - auto Parent = fileIndex(IncludingName); + auto Parent = getOrCreatefileIndex(IncludingName); IncludeChildren[Parent].push_back(Child); } -unsigned IncludeStructure::fileIndex(llvm::StringRef Name) { +IncludeStructure::File +IncludeStructure::getOrCreatefileIndex(llvm::StringRef Name) { auto R = NameToIndex.try_emplace(Name, RealPathNames.size()); if (R.second) RealPathNames.emplace_back(); return R.first->getValue(); } -llvm::StringMap -IncludeStructure::includeDepth(llvm::StringRef Root) const { +llvm::StringMap IncludeStructure::includeDepth(StringRef Name) const { // Include depth 0 is the main file only. llvm::StringMap Result; - Result[Root] = 0; + Result[Name] = 0; std::vector CurrentLevel; - llvm::DenseSet Seen; - auto It = NameToIndex.find(Root); - if (It != NameToIndex.end()) { - CurrentLevel.push_back(It->second); - Seen.insert(It->second); + llvm::DenseSet Seen; + auto Root = getFile(Name); + if (Root) { + CurrentLevel.push_back(*Root); + Seen.insert(*Root); + } else { + elog("Can not find the root ({0}) for includeDepth.", Name); } // Each round of BFS traversal finds the next depth level.