summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd')
-rw-r--r--clang-tools-extra/clangd/index/FileIndex.cpp76
-rw-r--r--clang-tools-extra/clangd/index/FileIndex.h17
-rw-r--r--clang-tools-extra/clangd/index/Index.h12
-rw-r--r--clang-tools-extra/clangd/index/MemIndex.cpp40
-rw-r--r--clang-tools-extra/clangd/index/MemIndex.h24
-rw-r--r--clang-tools-extra/clangd/index/Merge.cpp23
-rw-r--r--clang-tools-extra/clangd/index/Merge.h4
-rw-r--r--clang-tools-extra/clangd/tool/ClangdMain.cpp3
8 files changed, 169 insertions, 30 deletions
diff --git a/clang-tools-extra/clangd/index/FileIndex.cpp b/clang-tools-extra/clangd/index/FileIndex.cpp
index 48d05959dae..883faf9f398 100644
--- a/clang-tools-extra/clangd/index/FileIndex.cpp
+++ b/clang-tools-extra/clangd/index/FileIndex.cpp
@@ -16,9 +16,10 @@
namespace clang {
namespace clangd {
-SymbolSlab indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
- llvm::Optional<llvm::ArrayRef<Decl *>> TopLevelDecls,
- llvm::ArrayRef<std::string> URISchemes) {
+std::pair<SymbolSlab, SymbolOccurrenceSlab>
+indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
+ llvm::Optional<llvm::ArrayRef<Decl *>> TopLevelDecls,
+ llvm::ArrayRef<std::string> URISchemes) {
SymbolCollector::Options CollectorOpts;
// FIXME(ioeric): we might also want to collect include headers. We would need
// to make sure all includes are canonicalized (with CanonicalIncludes), which
@@ -31,8 +32,6 @@ SymbolSlab indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
CollectorOpts.URISchemes = URISchemes;
CollectorOpts.Origin = SymbolOrigin::Dynamic;
- SymbolCollector Collector(std::move(CollectorOpts));
- Collector.setPreprocessor(PP);
index::IndexingOptions IndexOpts;
// We only need declarations, because we don't count references.
IndexOpts.SystemSymbolFilter =
@@ -46,20 +45,45 @@ SymbolSlab indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
DeclsToIndex.assign(AST.getTranslationUnitDecl()->decls().begin(),
AST.getTranslationUnitDecl()->decls().end());
+ // We only collect occurrences when indexing main AST.
+ // FIXME: this is a hacky way to detect whether we are indexing preamble AST
+ // or main AST, we should make it explicitly.
+ bool IsIndexMainAST = TopLevelDecls.hasValue();
+ if (IsIndexMainAST)
+ CollectorOpts.OccurrenceFilter = AllOccurrenceKinds;
+
+ SymbolCollector Collector(std::move(CollectorOpts));
+ Collector.setPreprocessor(PP);
index::indexTopLevelDecls(AST, DeclsToIndex, Collector, IndexOpts);
- return Collector.takeSymbols();
+ const auto &SM = AST.getSourceManager();
+ const auto *MainFileEntry = SM.getFileEntryForID(SM.getMainFileID());
+ std::string FileName = MainFileEntry ? MainFileEntry->getName() : "";
+
+ auto Syms = Collector.takeSymbols();
+ auto Occurrences = Collector.takeOccurrences();
+ vlog("index {0}AST for {1}: \n"
+ " symbol slab: {2} symbols, {3} bytes\n"
+ " occurrence slab: {4} symbols, {5} bytes",
+ IsIndexMainAST ? "Main" : "Preamble", FileName, Syms.size(),
+ Syms.bytes(), Occurrences.size(), Occurrences.bytes());
+ return {std::move(Syms), std::move(Occurrences)};
}
FileIndex::FileIndex(std::vector<std::string> URISchemes)
: URISchemes(std::move(URISchemes)) {}
-void FileSymbols::update(PathRef Path, std::unique_ptr<SymbolSlab> Slab) {
+void FileSymbols::update(PathRef Path, std::unique_ptr<SymbolSlab> Slab,
+ std::unique_ptr<SymbolOccurrenceSlab> Occurrences) {
std::lock_guard<std::mutex> Lock(Mutex);
if (!Slab)
FileToSlabs.erase(Path);
else
FileToSlabs[Path] = std::move(Slab);
+ if (!Occurrences)
+ FileToOccurrenceSlabs.erase(Path);
+ else
+ FileToOccurrenceSlabs[Path] = std::move(Occurrences);
}
std::shared_ptr<std::vector<const Symbol *>> FileSymbols::allSymbols() {
@@ -85,19 +109,47 @@ std::shared_ptr<std::vector<const Symbol *>> FileSymbols::allSymbols() {
return {std::move(Snap), Pointers};
}
+std::shared_ptr<MemIndex::OccurrenceMap> FileSymbols::allOccurrences() const {
+ // The snapshot manages life time of symbol occurrence slabs and provides
+ // pointers to all occurrences in all occurrence slabs.
+ struct Snapshot {
+ MemIndex::OccurrenceMap Occurrences; // ID => {Occurrence}
+ std::vector<std::shared_ptr<SymbolOccurrenceSlab>> KeepAlive;
+ };
+
+ auto Snap = std::make_shared<Snapshot>();
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+
+ for (const auto &FileAndSlab : FileToOccurrenceSlabs) {
+ Snap->KeepAlive.push_back(FileAndSlab.second);
+ for (const auto &IDAndOccurrences : *FileAndSlab.second) {
+ auto &Occurrences = Snap->Occurrences[IDAndOccurrences.first];
+ for (const auto &Occurrence : IDAndOccurrences.second)
+ Occurrences.push_back(&Occurrence);
+ }
+ }
+ }
+
+ return {std::move(Snap), &Snap->Occurrences};
+}
+
void FileIndex::update(PathRef Path, ASTContext *AST,
std::shared_ptr<Preprocessor> PP,
llvm::Optional<llvm::ArrayRef<Decl *>> TopLevelDecls) {
if (!AST) {
- FSymbols.update(Path, nullptr);
+ FSymbols.update(Path, nullptr, nullptr);
} else {
assert(PP);
auto Slab = llvm::make_unique<SymbolSlab>();
- *Slab = indexAST(*AST, PP, TopLevelDecls, URISchemes);
- FSymbols.update(Path, std::move(Slab));
+ auto OccurrenceSlab = llvm::make_unique<SymbolOccurrenceSlab>();
+ auto IndexResults = indexAST(*AST, PP, TopLevelDecls, URISchemes);
+ std::tie(*Slab, *OccurrenceSlab) =
+ indexAST(*AST, PP, TopLevelDecls, URISchemes);
+ FSymbols.update(Path, std::move(Slab), std::move(OccurrenceSlab));
}
auto Symbols = FSymbols.allSymbols();
- Index.build(std::move(Symbols));
+ Index.build(std::move(Symbols), FSymbols.allOccurrences());
}
bool FileIndex::fuzzyFind(
@@ -115,7 +167,7 @@ void FileIndex::lookup(
void FileIndex::findOccurrences(
const OccurrencesRequest &Req,
llvm::function_ref<void(const SymbolOccurrence &)> Callback) const {
- log("findOccurrences is not implemented.");
+ Index.findOccurrences(Req, Callback);
}
size_t FileIndex::estimateMemoryUsage() const {
diff --git a/clang-tools-extra/clangd/index/FileIndex.h b/clang-tools-extra/clangd/index/FileIndex.h
index 58fad2f62e2..0794472885c 100644
--- a/clang-tools-extra/clangd/index/FileIndex.h
+++ b/clang-tools-extra/clangd/index/FileIndex.h
@@ -39,18 +39,25 @@ namespace clangd {
/// locking when we swap or obtain refereces to snapshots.
class FileSymbols {
public:
- /// \brief Updates all symbols in a file. If \p Slab is nullptr, symbols for
- /// \p Path will be removed.
- void update(PathRef Path, std::unique_ptr<SymbolSlab> Slab);
+ /// \brief Updates all symbols and occurrences in a file.
+ /// If \p Slab (Occurrence) is nullptr, symbols (occurrences) for \p Path
+ /// will be removed.
+ void update(PathRef Path, std::unique_ptr<SymbolSlab> Slab,
+ std::unique_ptr<SymbolOccurrenceSlab> Occurrences);
// The shared_ptr keeps the symbols alive
std::shared_ptr<std::vector<const Symbol *>> allSymbols();
+ /// Returns all symbol occurrences for all active files.
+ std::shared_ptr<MemIndex::OccurrenceMap> allOccurrences() const;
+
private:
mutable std::mutex Mutex;
/// \brief Stores the latest snapshots for all active files.
llvm::StringMap<std::shared_ptr<SymbolSlab>> FileToSlabs;
+ /// Stores the latest occurrence slabs for all active files.
+ llvm::StringMap<std::shared_ptr<SymbolOccurrenceSlab>> FileToOccurrenceSlabs;
};
/// \brief This manages symbls from files and an in-memory index on all symbols.
@@ -90,12 +97,12 @@ private:
std::vector<std::string> URISchemes;
};
-/// Retrieves namespace and class level symbols in \p AST.
+/// Retrieves symbols and symbol occurrences in \p AST.
/// Exposed to assist in unit tests.
/// If URISchemes is empty, the default schemes in SymbolCollector will be used.
/// If \p TopLevelDecls is set, only these decls are indexed. Otherwise, all top
/// level decls obtained from \p AST are indexed.
-SymbolSlab
+std::pair<SymbolSlab, SymbolOccurrenceSlab>
indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
llvm::Optional<llvm::ArrayRef<Decl *>> TopLevelDecls = llvm::None,
llvm::ArrayRef<std::string> URISchemes = {});
diff --git a/clang-tools-extra/clangd/index/Index.h b/clang-tools-extra/clangd/index/Index.h
index 12e0e7ebd51..410919bed06 100644
--- a/clang-tools-extra/clangd/index/Index.h
+++ b/clang-tools-extra/clangd/index/Index.h
@@ -344,6 +344,12 @@ public:
SymbolOccurrenceSlab() : UniqueStrings(Arena) {}
+ static SymbolOccurrenceSlab createEmpty() {
+ SymbolOccurrenceSlab Empty;
+ Empty.freeze();
+ return Empty;
+ }
+
// Define move semantics for the slab, allowing assignment from an rvalue.
// Implicit move assignment is deleted by the compiler because
// StringSaver has a reference type member.
@@ -360,6 +366,12 @@ public:
const_iterator begin() const { return Occurrences.begin(); }
const_iterator end() const { return Occurrences.end(); }
+ size_t bytes() const {
+ return sizeof(*this) + Arena.getTotalMemory() + Occurrences.getMemorySize();
+ }
+
+ size_t size() const { return Occurrences.size(); }
+
// Adds a symbol occurrence.
// This is a deep copy: underlying FileURI will be owned by the slab.
void insert(const SymbolID &SymID, const SymbolOccurrence &Occurrence);
diff --git a/clang-tools-extra/clangd/index/MemIndex.cpp b/clang-tools-extra/clangd/index/MemIndex.cpp
index 19a64ad9525..8d314d1febd 100644
--- a/clang-tools-extra/clangd/index/MemIndex.cpp
+++ b/clang-tools-extra/clangd/index/MemIndex.cpp
@@ -15,7 +15,27 @@
namespace clang {
namespace clangd {
-void MemIndex::build(std::shared_ptr<std::vector<const Symbol *>> Syms) {
+static std::shared_ptr<MemIndex::OccurrenceMap>
+getOccurrencesFromSlab(SymbolOccurrenceSlab OccurrencesSlab) {
+ struct Snapshot {
+ SymbolOccurrenceSlab Slab;
+ MemIndex::OccurrenceMap Occurrences;
+ };
+
+ auto Snap = std::make_shared<Snapshot>();
+ Snap->Slab = std::move(OccurrencesSlab);
+ for (const auto &IDAndOccurrences : Snap->Slab) {
+ auto &Occurrences = Snap->Occurrences[IDAndOccurrences.first];
+ for (const auto &Occurrence : IDAndOccurrences.second)
+ Occurrences.push_back(&Occurrence);
+ }
+ return {std::move(Snap), &Snap->Occurrences};
+}
+
+void MemIndex::build(std::shared_ptr<std::vector<const Symbol *>> Syms,
+ std::shared_ptr<OccurrenceMap> AllOccurrences) {
+ assert(Syms && "Syms must be set when build MemIndex");
+ assert(AllOccurrences && "Occurrences must be set when build MemIndex");
llvm::DenseMap<SymbolID, const Symbol *> TempIndex;
for (const Symbol *Sym : *Syms)
TempIndex[Sym->ID] = Sym;
@@ -25,15 +45,18 @@ void MemIndex::build(std::shared_ptr<std::vector<const Symbol *>> Syms) {
std::lock_guard<std::mutex> Lock(Mutex);
Index = std::move(TempIndex);
Symbols = std::move(Syms); // Relase old symbols.
+ Occurrences = std::move(AllOccurrences);
}
vlog("Built MemIndex with estimated memory usage {0} bytes.",
estimateMemoryUsage());
}
-std::unique_ptr<SymbolIndex> MemIndex::build(SymbolSlab Slab) {
+std::unique_ptr<SymbolIndex> MemIndex::build(SymbolSlab Symbols,
+ SymbolOccurrenceSlab Occurrences) {
auto Idx = llvm::make_unique<MemIndex>();
- Idx->build(getSymbolsFromSlab(std::move(Slab)));
+ Idx->build(getSymbolsFromSlab(std::move(Symbols)),
+ getOccurrencesFromSlab(std::move(Occurrences)));
return std::move(Idx);
}
@@ -84,7 +107,16 @@ void MemIndex::lookup(const LookupRequest &Req,
void MemIndex::findOccurrences(
const OccurrencesRequest &Req,
llvm::function_ref<void(const SymbolOccurrence &)> Callback) const {
- log("findOccurrences is not implemented.");
+ std::lock_guard<std::mutex> Lock(Mutex);
+ for (const auto &ReqID : Req.IDs) {
+ auto FoundOccurrences = Occurrences->find(ReqID);
+ if (FoundOccurrences == Occurrences->end())
+ continue;
+ for (const auto *O : FoundOccurrences->second) {
+ if (static_cast<int>(Req.Filter & O->Kind))
+ Callback(*O);
+ }
+ }
}
std::shared_ptr<std::vector<const Symbol *>>
diff --git a/clang-tools-extra/clangd/index/MemIndex.h b/clang-tools-extra/clangd/index/MemIndex.h
index feca87af5e4..6d16afa5b5d 100644
--- a/clang-tools-extra/clangd/index/MemIndex.h
+++ b/clang-tools-extra/clangd/index/MemIndex.h
@@ -16,16 +16,24 @@
namespace clang {
namespace clangd {
-/// \brief This implements an index for a (relatively small) set of symbols that
-/// can be easily managed in memory.
+/// \brief This implements an index for a (relatively small) set of symbols (or
+/// symbol occurrences) that can be easily managed in memory.
class MemIndex : public SymbolIndex {
public:
- /// \brief (Re-)Build index for `Symbols`. All symbol pointers must remain
- /// accessible as long as `Symbols` is kept alive.
- void build(std::shared_ptr<std::vector<const Symbol *>> Symbols);
+ /// Maps from a symbol ID to all corresponding symbol occurrences.
+ /// The map doesn't own occurrence objects.
+ using OccurrenceMap =
+ llvm::DenseMap<SymbolID, std::vector<const SymbolOccurrence *>>;
- /// \brief Build index from a symbol slab.
- static std::unique_ptr<SymbolIndex> build(SymbolSlab Slab);
+ /// \brief (Re-)Build index for `Symbols` and update `Occurrences`.
+ /// All symbol pointers and symbol occurrence pointers must remain accessible
+ /// as long as `Symbols` and `Occurrences` are kept alive.
+ void build(std::shared_ptr<std::vector<const Symbol *>> Symbols,
+ std::shared_ptr<OccurrenceMap> Occurrences);
+
+ /// \brief Build index from a symbol slab and a symbol occurrence slab.
+ static std::unique_ptr<SymbolIndex> build(SymbolSlab Symbols,
+ SymbolOccurrenceSlab Occurrences);
bool
fuzzyFind(const FuzzyFindRequest &Req,
@@ -47,6 +55,8 @@ private:
// Index is a set of symbols that are deduplicated by symbol IDs.
// FIXME: build smarter index structure.
llvm::DenseMap<SymbolID, const Symbol *> Index;
+ // A map from symbol ID to symbol occurrences, support query by IDs.
+ std::shared_ptr<OccurrenceMap> Occurrences;
mutable std::mutex Mutex;
};
diff --git a/clang-tools-extra/clangd/index/Merge.cpp b/clang-tools-extra/clangd/index/Merge.cpp
index 2f49aa2b2f0..27a47854497 100644
--- a/clang-tools-extra/clangd/index/Merge.cpp
+++ b/clang-tools-extra/clangd/index/Merge.cpp
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+#include <set>
+
#include "Merge.h"
#include "../Logger.h"
#include "llvm/ADT/STLExtras.h"
@@ -79,7 +81,26 @@ class MergedIndex : public SymbolIndex {
void findOccurrences(const OccurrencesRequest &Req,
llvm::function_ref<void(const SymbolOccurrence &)>
Callback) const override {
- log("findOccurrences is not implemented.");
+ // We don't want duplicated occurrences from the static/dynamic indexes,
+ // and we can't reliably duplicate them because occurrence offsets may
+ // differ slightly.
+ // We consider the dynamic index authoritative and report all its
+ // occurrences, and only report static index occurrences from other files.
+ //
+ // FIXME: The heuristic fails if the dynamic index containts a file, but all
+ // occurrences were removed (we will report stale ones from the static
+ // index). Ultimately we should explicit check which index has the file
+ // instead.
+ std::set<std::string> DynamicIndexFileURIs;
+ Dynamic->findOccurrences(Req, [&](const SymbolOccurrence &O) {
+ DynamicIndexFileURIs.insert(O.Location.FileURI);
+ Callback(O);
+ });
+ Static->findOccurrences(Req, [&](const SymbolOccurrence &O) {
+ if (DynamicIndexFileURIs.count(O.Location.FileURI))
+ return;
+ Callback(O);
+ });
}
size_t estimateMemoryUsage() const override {
diff --git a/clang-tools-extra/clangd/index/Merge.h b/clang-tools-extra/clangd/index/Merge.h
index 281ae01710c..38a6887040c 100644
--- a/clang-tools-extra/clangd/index/Merge.h
+++ b/clang-tools-extra/clangd/index/Merge.h
@@ -24,6 +24,10 @@ Symbol mergeSymbol(const Symbol &L, const Symbol &R);
// - the Dynamic index covers few files, but is relatively up-to-date.
// - the Static index covers a bigger set of files, but is relatively stale.
// The returned index attempts to combine results, and avoid duplicates.
+//
+// FIXME: We don't have a mechanism in Index to track deleted symbols and
+// occurrences in dirty files, so the merged index may return stale symbols
+// and occurrences from Static index.
std::unique_ptr<SymbolIndex> mergeIndex(const SymbolIndex *Dynamic,
const SymbolIndex *Static);
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 52c76400f35..cf5c7fac015 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -54,7 +54,8 @@ std::unique_ptr<SymbolIndex> buildStaticIndex(llvm::StringRef YamlSymbolFile) {
SymsBuilder.insert(Sym);
return UseDex ? dex::DexIndex::build(std::move(SymsBuilder).build())
- : MemIndex::build(std::move(SymsBuilder).build());
+ : MemIndex::build(std::move(SymsBuilder).build(),
+ SymbolOccurrenceSlab::createEmpty());
}
} // namespace
OpenPOWER on IntegriCloud