2018-08-15 00:03:32 +08:00
|
|
|
//===--- Merge.cpp -----------------------------------------------*- C++-*-===//
|
2018-01-15 20:33:00 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
2018-08-15 00:03:32 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-01-15 20:33:00 +08:00
|
|
|
#include "Merge.h"
|
2018-08-06 21:14:32 +08:00
|
|
|
#include "../Logger.h"
|
2018-01-15 20:33:00 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2018-01-15 20:33:00 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
#include <set>
|
2018-08-15 00:03:32 +08:00
|
|
|
|
2018-01-15 20:33:00 +08:00
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
2018-08-15 00:03:32 +08:00
|
|
|
|
2018-01-15 20:33:00 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
class MergedIndex : public SymbolIndex {
|
|
|
|
public:
|
|
|
|
MergedIndex(const SymbolIndex *Dynamic, const SymbolIndex *Static)
|
|
|
|
: Dynamic(Dynamic), Static(Static) {}
|
|
|
|
|
|
|
|
// FIXME: Deleted symbols in dirty files are still returned (from Static).
|
|
|
|
// To identify these eliminate these, we should:
|
|
|
|
// - find the generating file from each Symbol which is Static-only
|
|
|
|
// - ask Dynamic if it has that file (needs new SymbolIndex method)
|
|
|
|
// - if so, drop the Symbol.
|
[clangd] Pass Context implicitly using TLS.
Summary:
Instead of passing Context explicitly around, we now have a thread-local
Context object `Context::current()` which is an implicit argument to
every function.
Most manipulation of this should use the WithContextValue helper, which
augments the current Context to add a single KV pair, and restores the
old context on destruction.
Advantages are:
- less boilerplate in functions that just propagate contexts
- reading most code doesn't require understanding context at all, and
using context as values in fewer places still
- fewer options to pass the "wrong" context when it changes within a
scope (e.g. when using Span)
- contexts pass through interfaces we can't modify, such as VFS
- propagating contexts across threads was slightly tricky (e.g.
copy vs move, no move-init in lambdas), and is now encapsulated in
the threadpool
Disadvantages are all the usual TLS stuff - hidden magic, and
potential for higher memory usage on threads that don't use the
context. (In practice, it's just one pointer)
Reviewers: ilya-biryukov
Subscribers: klimek, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D42517
llvm-svn: 323872
2018-01-31 21:40:48 +08:00
|
|
|
bool fuzzyFind(const FuzzyFindRequest &Req,
|
2018-01-15 20:33:00 +08:00
|
|
|
function_ref<void(const Symbol &)> Callback) const override {
|
|
|
|
// We can't step through both sources in parallel. So:
|
|
|
|
// 1) query all dynamic symbols, slurping results into a slab
|
|
|
|
// 2) query the static symbols, for each one:
|
|
|
|
// a) if it's not in the dynamic slab, yield it directly
|
|
|
|
// b) if it's in the dynamic slab, merge it and yield the result
|
|
|
|
// 3) now yield all the dynamic symbols we haven't processed.
|
|
|
|
bool More = false; // We'll be incomplete if either source was.
|
|
|
|
SymbolSlab::Builder DynB;
|
[clangd] Pass Context implicitly using TLS.
Summary:
Instead of passing Context explicitly around, we now have a thread-local
Context object `Context::current()` which is an implicit argument to
every function.
Most manipulation of this should use the WithContextValue helper, which
augments the current Context to add a single KV pair, and restores the
old context on destruction.
Advantages are:
- less boilerplate in functions that just propagate contexts
- reading most code doesn't require understanding context at all, and
using context as values in fewer places still
- fewer options to pass the "wrong" context when it changes within a
scope (e.g. when using Span)
- contexts pass through interfaces we can't modify, such as VFS
- propagating contexts across threads was slightly tricky (e.g.
copy vs move, no move-init in lambdas), and is now encapsulated in
the threadpool
Disadvantages are all the usual TLS stuff - hidden magic, and
potential for higher memory usage on threads that don't use the
context. (In practice, it's just one pointer)
Reviewers: ilya-biryukov
Subscribers: klimek, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D42517
llvm-svn: 323872
2018-01-31 21:40:48 +08:00
|
|
|
More |= Dynamic->fuzzyFind(Req, [&](const Symbol &S) { DynB.insert(S); });
|
2018-01-15 20:33:00 +08:00
|
|
|
SymbolSlab Dyn = std::move(DynB).build();
|
|
|
|
|
|
|
|
DenseSet<SymbolID> SeenDynamicSymbols;
|
[clangd] Pass Context implicitly using TLS.
Summary:
Instead of passing Context explicitly around, we now have a thread-local
Context object `Context::current()` which is an implicit argument to
every function.
Most manipulation of this should use the WithContextValue helper, which
augments the current Context to add a single KV pair, and restores the
old context on destruction.
Advantages are:
- less boilerplate in functions that just propagate contexts
- reading most code doesn't require understanding context at all, and
using context as values in fewer places still
- fewer options to pass the "wrong" context when it changes within a
scope (e.g. when using Span)
- contexts pass through interfaces we can't modify, such as VFS
- propagating contexts across threads was slightly tricky (e.g.
copy vs move, no move-init in lambdas), and is now encapsulated in
the threadpool
Disadvantages are all the usual TLS stuff - hidden magic, and
potential for higher memory usage on threads that don't use the
context. (In practice, it's just one pointer)
Reviewers: ilya-biryukov
Subscribers: klimek, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D42517
llvm-svn: 323872
2018-01-31 21:40:48 +08:00
|
|
|
More |= Static->fuzzyFind(Req, [&](const Symbol &S) {
|
2018-01-15 20:33:00 +08:00
|
|
|
auto DynS = Dyn.find(S.ID);
|
|
|
|
if (DynS == Dyn.end())
|
|
|
|
return Callback(S);
|
|
|
|
SeenDynamicSymbols.insert(S.ID);
|
2018-08-31 21:55:01 +08:00
|
|
|
Callback(mergeSymbol(*DynS, S));
|
2018-01-15 20:33:00 +08:00
|
|
|
});
|
|
|
|
for (const Symbol &S : Dyn)
|
|
|
|
if (!SeenDynamicSymbols.count(S.ID))
|
|
|
|
Callback(S);
|
2018-02-19 21:04:41 +08:00
|
|
|
return More;
|
2018-01-15 20:33:00 +08:00
|
|
|
}
|
|
|
|
|
2018-03-14 17:48:05 +08:00
|
|
|
void
|
|
|
|
lookup(const LookupRequest &Req,
|
|
|
|
llvm::function_ref<void(const Symbol &)> Callback) const override {
|
|
|
|
SymbolSlab::Builder B;
|
|
|
|
|
|
|
|
Dynamic->lookup(Req, [&](const Symbol &S) { B.insert(S); });
|
|
|
|
|
|
|
|
auto RemainingIDs = Req.IDs;
|
|
|
|
Static->lookup(Req, [&](const Symbol &S) {
|
|
|
|
const Symbol *Sym = B.find(S.ID);
|
|
|
|
RemainingIDs.erase(S.ID);
|
|
|
|
if (!Sym)
|
|
|
|
Callback(S);
|
|
|
|
else
|
2018-08-31 21:55:01 +08:00
|
|
|
Callback(mergeSymbol(*Sym, S));
|
2018-03-14 17:48:05 +08:00
|
|
|
});
|
|
|
|
for (const auto &ID : RemainingIDs)
|
|
|
|
if (const Symbol *Sym = B.find(ID))
|
|
|
|
Callback(*Sym);
|
|
|
|
}
|
|
|
|
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
void refs(const RefsRequest &Req,
|
|
|
|
llvm::function_ref<void(const Ref &)> Callback) const override {
|
|
|
|
// We don't want duplicated refs from the static/dynamic indexes,
|
|
|
|
// and we can't reliably duplicate them because offsets may differ slightly.
|
|
|
|
// We consider the dynamic index authoritative and report all its refs,
|
|
|
|
// and only report static index refs from other files.
|
2018-09-01 03:53:37 +08:00
|
|
|
//
|
2018-09-01 15:47:03 +08:00
|
|
|
// FIXME: The heuristic fails if the dynamic index contains a file, but all
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
// refs were removed (we will report stale ones from the static index).
|
|
|
|
// Ultimately we should explicit check which index has the file instead.
|
|
|
|
llvm::StringSet<> DynamicIndexFileURIs;
|
|
|
|
Dynamic->refs(Req, [&](const Ref &O) {
|
2018-09-01 03:53:37 +08:00
|
|
|
DynamicIndexFileURIs.insert(O.Location.FileURI);
|
|
|
|
Callback(O);
|
|
|
|
});
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
Static->refs(Req, [&](const Ref &O) {
|
|
|
|
if (!DynamicIndexFileURIs.count(O.Location.FileURI))
|
|
|
|
Callback(O);
|
2018-09-01 03:53:37 +08:00
|
|
|
});
|
2018-08-06 21:14:32 +08:00
|
|
|
}
|
|
|
|
|
2018-08-24 17:12:54 +08:00
|
|
|
size_t estimateMemoryUsage() const override {
|
|
|
|
return Dynamic->estimateMemoryUsage() + Static->estimateMemoryUsage();
|
|
|
|
}
|
|
|
|
|
2018-01-15 20:33:00 +08:00
|
|
|
private:
|
|
|
|
const SymbolIndex *Dynamic, *Static;
|
|
|
|
};
|
2018-07-26 20:05:31 +08:00
|
|
|
} // namespace
|
2018-01-15 20:33:00 +08:00
|
|
|
|
2018-08-31 21:55:01 +08:00
|
|
|
Symbol mergeSymbol(const Symbol &L, const Symbol &R) {
|
2018-01-15 20:33:00 +08:00
|
|
|
assert(L.ID == R.ID);
|
2018-02-09 22:42:01 +08:00
|
|
|
// We prefer information from TUs that saw the definition.
|
|
|
|
// Classes: this is the def itself. Functions: hopefully the header decl.
|
|
|
|
// If both did (or both didn't), continue to prefer L over R.
|
|
|
|
bool PreferR = R.Definition && !L.Definition;
|
[clangd] Support multiple #include headers in one symbol.
Summary:
Currently, a symbol can have only one #include header attached, which
might not work well if the symbol can be imported via different #includes depending
on where it's used. This patch stores multiple #include headers (with # references)
for each symbol, so that CodeCompletion can decide which include to insert.
In this patch, code completion simply picks the most popular include as the default inserted header. We also return all possible includes and their edits in the `CodeCompletion` results.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: mgrang, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51291
llvm-svn: 341304
2018-09-03 18:18:21 +08:00
|
|
|
// Merge include headers only if both have definitions or both have no
|
|
|
|
// definition; otherwise, only accumulate references of common includes.
|
|
|
|
bool MergeIncludes =
|
|
|
|
L.Definition.FileURI.empty() == R.Definition.FileURI.empty();
|
2018-02-09 22:42:01 +08:00
|
|
|
Symbol S = PreferR ? R : L; // The target symbol we're merging into.
|
|
|
|
const Symbol &O = PreferR ? L : R; // The "other" less-preferred symbol.
|
|
|
|
|
|
|
|
// For each optional field, fill it from O if missing in S.
|
|
|
|
// (It might be missing in O too, but that's a no-op).
|
|
|
|
if (!S.Definition)
|
|
|
|
S.Definition = O.Definition;
|
|
|
|
if (!S.CanonicalDeclaration)
|
|
|
|
S.CanonicalDeclaration = O.CanonicalDeclaration;
|
2018-03-12 22:49:09 +08:00
|
|
|
S.References += O.References;
|
2018-06-23 00:11:35 +08:00
|
|
|
if (S.Signature == "")
|
|
|
|
S.Signature = O.Signature;
|
|
|
|
if (S.CompletionSnippetSuffix == "")
|
|
|
|
S.CompletionSnippetSuffix = O.CompletionSnippetSuffix;
|
2018-08-31 21:55:01 +08:00
|
|
|
if (S.Documentation == "")
|
|
|
|
S.Documentation = O.Documentation;
|
|
|
|
if (S.ReturnType == "")
|
|
|
|
S.ReturnType = O.ReturnType;
|
[clangd] Support multiple #include headers in one symbol.
Summary:
Currently, a symbol can have only one #include header attached, which
might not work well if the symbol can be imported via different #includes depending
on where it's used. This patch stores multiple #include headers (with # references)
for each symbol, so that CodeCompletion can decide which include to insert.
In this patch, code completion simply picks the most popular include as the default inserted header. We also return all possible includes and their edits in the `CodeCompletion` results.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: mgrang, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51291
llvm-svn: 341304
2018-09-03 18:18:21 +08:00
|
|
|
for (const auto &OI : O.IncludeHeaders) {
|
|
|
|
bool Found = false;
|
|
|
|
for (auto &SI : S.IncludeHeaders) {
|
|
|
|
if (SI.IncludeHeader == OI.IncludeHeader) {
|
|
|
|
Found = true;
|
|
|
|
SI.References += OI.References;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!Found && MergeIncludes)
|
|
|
|
S.IncludeHeaders.emplace_back(OI.IncludeHeader, OI.References);
|
|
|
|
}
|
2018-07-05 14:20:41 +08:00
|
|
|
|
2018-07-06 19:50:49 +08:00
|
|
|
S.Origin |= O.Origin | SymbolOrigin::Merge;
|
2018-01-15 20:33:00 +08:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<SymbolIndex> mergeIndex(const SymbolIndex *Dynamic,
|
|
|
|
const SymbolIndex *Static) {
|
|
|
|
return llvm::make_unique<MergedIndex>(Dynamic, Static);
|
|
|
|
}
|
2018-08-15 00:03:32 +08:00
|
|
|
|
2018-01-15 20:33:00 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|