diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt --- a/clang-tools-extra/clangd/CMakeLists.txt +++ b/clang-tools-extra/clangd/CMakeLists.txt @@ -93,6 +93,7 @@ index/IndexAction.cpp index/MemIndex.cpp index/Merge.cpp + index/ProjectAware.cpp index/Ref.cpp index/Relation.cpp index/Serialization.cpp diff --git a/clang-tools-extra/clangd/index/ProjectAware.h b/clang-tools-extra/clangd/index/ProjectAware.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/ProjectAware.h @@ -0,0 +1,76 @@ +//===--- ProjectAware.h ------------------------------------------*- C++-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_PROJECT_AWARE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_PROJECT_AWARE_H + +#include "Config.h" +#include "index/Index.h" +#include "index/MemIndex.h" +#include "index/Merge.h" +#include "index/Serialization.h" +#include "index/remote/Client.h" +#include "support/Threading.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include +#include +#include +#include +#include +namespace clang { +namespace clangd { + +class ProjectAwareIndex : public SymbolIndex { +public: + size_t estimateMemoryUsage() const override; + + /// Only queries the associated index with the current context. + void lookup(const LookupRequest &Req, + llvm::function_ref Callback) const override; + + /// Query all indexes while prioritizing the associated one (if any). + bool refs(const RefsRequest &Req, + llvm::function_ref Callback) const override; + + /// Queries only the associates index when Req.RestrictForCodeCompletion is + /// set, otherwise queries all. + bool + fuzzyFind(const FuzzyFindRequest &Req, + llvm::function_ref Callback) const override; + + /// Query all indexes while prioritizing the associated one (if any). + void relations(const RelationsRequest &Req, + llvm::function_ref + Callback) const override; + +private: + // Returns the index associated with current context, if any. + SymbolIndex *getIndex() const; + // Adds the Idx into IndexStorage and adjusts the MergedIdx view. Returns a + // pointer to the Idx. + SymbolIndex *addIndex(std::unique_ptr Idx) const; + + // Storage for all the external indexes. + Memoize> IndexForProject; + mutable std::mutex Mu; + mutable std::vector> IndexStorage; + AsyncTaskRunner Tasks; + + // Used for creating a merged view over all the indexes seen so far to ease + // querying them all at once. + mutable std::mutex MergedIdxMu; + mutable std::vector> MergedIdxStorage; + // Points at root of merged view of all smybols. + mutable SymbolIndex *MergedIdx = nullptr; +}; +} // namespace clangd +} // namespace clang + +#endif diff --git a/clang-tools-extra/clangd/index/ProjectAware.cpp b/clang-tools-extra/clangd/index/ProjectAware.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/ProjectAware.cpp @@ -0,0 +1,125 @@ +//===--- ProjectAware.h ------------------------------------------*- C++-*-===// +// +// 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 "ProjectAware.h" +#include "index/Index.h" +#include "index/Merge.h" +#include "index/Ref.h" +#include "index/Symbol.h" +#include "index/SymbolID.h" +#include "support/Logger.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include +#include + +namespace clang { +namespace clangd { +size_t ProjectAwareIndex::estimateMemoryUsage() const { + size_t Total = 0; + std::lock_guard Lock(Mu); + for (auto &Idx : IndexStorage) + Total += Idx->estimateMemoryUsage(); + return Total; +} + +void ProjectAwareIndex::lookup( + const LookupRequest &Req, + llvm::function_ref Callback) const { + if (auto *Idx = getIndex()) + Idx->lookup(Req, Callback); +} + +bool ProjectAwareIndex::refs( + const RefsRequest &Req, + llvm::function_ref Callback) const { + auto *AssocIdx = getIndex(); + std::lock_guard Lock(MergedIdxMu); + if (AssocIdx) + return MergedIndex(AssocIdx, MergedIdx).refs(Req, Callback); + return MergedIdx->refs(Req, Callback); +} + +bool ProjectAwareIndex::fuzzyFind( + const FuzzyFindRequest &Req, + llvm::function_ref Callback) const { + auto *AssocIdx = getIndex(); + if (Req.RestrictForCodeCompletion) { + if (AssocIdx) + return AssocIdx->fuzzyFind(Req, Callback); + return false; + } + std::lock_guard Lock(MergedIdxMu); + if (AssocIdx) + return MergedIndex(AssocIdx, MergedIdx).fuzzyFind(Req, Callback); + return MergedIdx->fuzzyFind(Req, Callback); +} + +void ProjectAwareIndex::relations( + const RelationsRequest &Req, + llvm::function_ref Callback) const { + auto *AssocIdx = getIndex(); + std::lock_guard Lock(MergedIdxMu); + if (AssocIdx) + return MergedIndex(AssocIdx, MergedIdx).relations(Req, Callback); + return MergedIdx->relations(Req, Callback); +} + +SymbolIndex *ProjectAwareIndex::getIndex() const { + const auto &C = Config::current(); + if (C.Index.External.MountPoint.empty()) + return nullptr; + if (auto File = C.Index.External.File) { + return IndexForProject.get( + *File, [File = std::move(*File), + MP = llvm::StringRef(C.Index.External.MountPoint), this] { + log("Associating {0} with monolithic index at {1}.", MP, File); + auto NewIndex = + std::make_unique(std::make_unique()); + SwapIndex *PlaceHolder = NewIndex.get(); + Tasks.runAsync("Load-index:" + File, [File, PlaceHolder] { + if (auto Idx = loadIndex(File, /*UseDex=*/true)) + PlaceHolder->reset(std::move(Idx)); + }); + addIndex(std::move(NewIndex)); + return PlaceHolder; + }); + } + assert(C.Index.External.Server); + auto Server = std::move(*C.Index.External.Server); + return IndexForProject.get( + Server, [Server = std::move(Server), + MP = llvm::StringRef(C.Index.External.MountPoint), this] { + log("Associating {0} with remote index at {1}.", MP, Server); + auto NewIndex = remote::getClient(Server, MP); + return addIndex(std::move(NewIndex)); + }); +} + +SymbolIndex * +ProjectAwareIndex::addIndex(std::unique_ptr Idx) const { + SymbolIndex *NewIdx = Idx.get(); + { + std::lock_guard Lock(Mu); + IndexStorage.emplace_back(std::move(Idx)); + } + { + std::lock_guard Lock(MergedIdxMu); + if (!MergedIdx) + MergedIdx = NewIdx; + else { + MergedIdxStorage.emplace_back( + std::make_unique(NewIdx, MergedIdx)); + MergedIdx = MergedIdxStorage.back().get(); + } + } + return NewIdx; +} +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt --- a/clang-tools-extra/clangd/unittests/CMakeLists.txt +++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt @@ -73,6 +73,7 @@ PathMappingTests.cpp PreambleTests.cpp PrintASTTests.cpp + ProjectAwareIndexTests.cpp QualityTests.cpp RenameTests.cpp RIFFTests.cpp diff --git a/clang-tools-extra/clangd/unittests/ProjectAwareIndexTests.cpp b/clang-tools-extra/clangd/unittests/ProjectAwareIndexTests.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/unittests/ProjectAwareIndexTests.cpp @@ -0,0 +1,7 @@ +//===-- ProjectAwareIndexTests.cpp -------------------*- C++ -*-----------===// +// +// 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 +// +//===----------------------------------------------------------------------===//