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,59 @@ +//===--- 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 <cstddef> +#include <list> +#include <memory> +#include <mutex> +#include <string> +namespace clang { +namespace clangd { + +class ProjectAwareIndex : public SymbolIndex { +public: + size_t estimateMemoryUsage() const override; + + void lookup(const LookupRequest &Req, + llvm::function_ref<void(const Symbol &)> Callback) const override; + + bool refs(const RefsRequest &Req, + llvm::function_ref<void(const Ref &)> Callback) const override; + + bool + fuzzyFind(const FuzzyFindRequest &Req, + llvm::function_ref<void(const Symbol &)> Callback) const override; + + void relations(const RelationsRequest &Req, + llvm::function_ref<void(const SymbolID &, const Symbol &)> + Callback) const override; + +private: + SymbolIndex *getIndex() const; + + Memoize<llvm::StringMap<SymbolIndex *>> IndexForProject; + mutable std::mutex Mu; + mutable std::list<std::unique_ptr<SymbolIndex>> IndexStorage; + AsyncTaskRunner Tasks; +}; +} // 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,88 @@ +//===--- 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 "support/Logger.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace clangd { +size_t ProjectAwareIndex::estimateMemoryUsage() const { + size_t Total = 0; + std::lock_guard<std::mutex> Lock(Mu); + for (auto &Idx : IndexStorage) + Total += Idx->estimateMemoryUsage(); + return Total; +} + +void ProjectAwareIndex::lookup( + const LookupRequest &Req, + llvm::function_ref<void(const Symbol &)> Callback) const { + if (auto *Idx = getIndex()) + Idx->lookup(Req, Callback); +} + +bool ProjectAwareIndex::refs( + const RefsRequest &Req, + llvm::function_ref<void(const Ref &)> Callback) const { + if (auto *Idx = getIndex()) + return Idx->refs(Req, Callback); + return false; +} + +bool ProjectAwareIndex::fuzzyFind( + const FuzzyFindRequest &Req, + llvm::function_ref<void(const Symbol &)> Callback) const { + if (auto *Idx = getIndex()) + return Idx->fuzzyFind(Req, Callback); + return false; +} + +void ProjectAwareIndex::relations( + const RelationsRequest &Req, + llvm::function_ref<void(const SymbolID &, const Symbol &)> Callback) const { + if (auto *Idx = getIndex()) + Idx->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<SwapIndex>(std::make_unique<MemIndex>()); + SwapIndex *PlaceHolder = NewIndex.get(); + Tasks.runAsync("Load-index:" + File, [File, PlaceHolder] { + if (auto Idx = loadIndex(File, /*UseDex=*/true)) + PlaceHolder->reset(std::move(Idx)); + }); + std::lock_guard<std::mutex> Lock(Mu); + IndexStorage.emplace_back(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); + std::lock_guard<std::mutex> Lock(Mu); + IndexStorage.emplace_back(std::move(NewIndex)); + return IndexStorage.back().get(); + }); +} + +} // 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 +// +//===----------------------------------------------------------------------===//