-
Notifications
You must be signed in to change notification settings - Fork 10.7k
/
Merge.cpp
143 lines (125 loc) · 4.87 KB
/
Merge.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//===--- Merge.cpp -----------------------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Merge.h"
#include "../Logger.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
namespace clangd {
namespace {
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.
bool fuzzyFind(const FuzzyFindRequest &Req,
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;
More |= Dynamic->fuzzyFind(Req, [&](const Symbol &S) { DynB.insert(S); });
SymbolSlab Dyn = std::move(DynB).build();
DenseSet<SymbolID> SeenDynamicSymbols;
Symbol::Details Scratch;
More |= Static->fuzzyFind(Req, [&](const Symbol &S) {
auto DynS = Dyn.find(S.ID);
if (DynS == Dyn.end())
return Callback(S);
SeenDynamicSymbols.insert(S.ID);
Callback(mergeSymbol(*DynS, S, &Scratch));
});
for (const Symbol &S : Dyn)
if (!SeenDynamicSymbols.count(S.ID))
Callback(S);
return More;
}
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;
Symbol::Details Scratch;
Static->lookup(Req, [&](const Symbol &S) {
const Symbol *Sym = B.find(S.ID);
RemainingIDs.erase(S.ID);
if (!Sym)
Callback(S);
else
Callback(mergeSymbol(*Sym, S, &Scratch));
});
for (const auto &ID : RemainingIDs)
if (const Symbol *Sym = B.find(ID))
Callback(*Sym);
}
void findOccurrences(const OccurrencesRequest &Req,
llvm::function_ref<void(const SymbolOccurrence &)>
Callback) const override {
log("findOccurrences is not implemented.");
}
size_t estimateMemoryUsage() const override {
return Dynamic->estimateMemoryUsage() + Static->estimateMemoryUsage();
}
private:
const SymbolIndex *Dynamic, *Static;
};
} // namespace
Symbol
mergeSymbol(const Symbol &L, const Symbol &R, Symbol::Details *Scratch) {
assert(L.ID == R.ID);
// 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;
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;
S.References += O.References;
if (S.Signature == "")
S.Signature = O.Signature;
if (S.CompletionSnippetSuffix == "")
S.CompletionSnippetSuffix = O.CompletionSnippetSuffix;
if (O.Detail) {
if (S.Detail) {
// Copy into scratch space so we can merge.
*Scratch = *S.Detail;
if (Scratch->Documentation == "")
Scratch->Documentation = O.Detail->Documentation;
if (Scratch->ReturnType == "")
Scratch->ReturnType = O.Detail->ReturnType;
if (Scratch->IncludeHeader == "")
Scratch->IncludeHeader = O.Detail->IncludeHeader;
S.Detail = Scratch;
} else
S.Detail = O.Detail;
}
S.Origin |= O.Origin | SymbolOrigin::Merge;
return S;
}
std::unique_ptr<SymbolIndex> mergeIndex(const SymbolIndex *Dynamic,
const SymbolIndex *Static) {
return llvm::make_unique<MergedIndex>(Dynamic, Static);
}
} // namespace clangd
} // namespace clang