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
|
//===--- Index.cpp -----------------------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Index.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/SHA1.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
namespace clangd {
using namespace llvm;
raw_ostream &operator<<(raw_ostream &OS, const SymbolLocation &L) {
if (!L)
return OS << "(none)";
return OS << L.FileURI << "[" << L.Start.Line << ":" << L.Start.Column << "-"
<< L.End.Line << ":" << L.End.Column << ")";
}
SymbolID::SymbolID(StringRef USR)
: HashValue(SHA1::hash(arrayRefFromStringRef(USR))) {}
raw_ostream &operator<<(raw_ostream &OS, const SymbolID &ID) {
OS << toHex(toStringRef(ID.HashValue));
return OS;
}
std::string SymbolID::str() const {
std::string ID;
llvm::raw_string_ostream OS(ID);
OS << *this;
return OS.str();
}
void operator>>(StringRef Str, SymbolID &ID) {
std::string HexString = fromHex(Str);
assert(HexString.size() == ID.HashValue.size());
std::copy(HexString.begin(), HexString.end(), ID.HashValue.begin());
}
raw_ostream &operator<<(raw_ostream &OS, SymbolOrigin O) {
if (O == SymbolOrigin::Unknown)
return OS << "unknown";
constexpr static char Sigils[] = "ADSM4567";
for (unsigned I = 0; I < sizeof(Sigils); ++I)
if (static_cast<uint8_t>(O) & 1u << I)
OS << Sigils[I];
return OS;
}
raw_ostream &operator<<(raw_ostream &OS, const Symbol &S) {
return OS << S.Scope << S.Name;
}
double quality(const Symbol &S) {
// This avoids a sharp gradient for tail symbols, and also neatly avoids the
// question of whether 0 references means a bad symbol or missing data.
if (S.References < 3)
return 1;
return std::log(S.References);
}
SymbolSlab::const_iterator SymbolSlab::find(const SymbolID &ID) const {
auto It = std::lower_bound(Symbols.begin(), Symbols.end(), ID,
[](const Symbol &S, const SymbolID &I) {
return S.ID < I;
});
if (It != Symbols.end() && It->ID == ID)
return It;
return Symbols.end();
}
// Copy the underlying data of the symbol into the owned arena.
static void own(Symbol &S, DenseSet<StringRef> &Strings,
BumpPtrAllocator &Arena) {
// Intern replaces V with a reference to the same string owned by the arena.
auto Intern = [&](StringRef &V) {
auto R = Strings.insert(V);
if (R.second) { // New entry added to the table, copy the string.
*R.first = V.copy(Arena);
}
V = *R.first;
};
// We need to copy every StringRef field onto the arena.
Intern(S.Name);
Intern(S.Scope);
Intern(S.CanonicalDeclaration.FileURI);
Intern(S.Definition.FileURI);
Intern(S.Signature);
Intern(S.CompletionSnippetSuffix);
if (S.Detail) {
// Copy values of StringRefs into arena.
auto *Detail = Arena.Allocate<Symbol::Details>();
*Detail = *S.Detail;
// Intern the actual strings.
Intern(Detail->Documentation);
Intern(Detail->ReturnType);
Intern(Detail->IncludeHeader);
// Replace the detail pointer with our copy.
S.Detail = Detail;
}
}
void SymbolSlab::Builder::insert(const Symbol &S) {
auto R = SymbolIndex.try_emplace(S.ID, Symbols.size());
if (R.second) {
Symbols.push_back(S);
own(Symbols.back(), Strings, Arena);
} else {
auto &Copy = Symbols[R.first->second] = S;
own(Copy, Strings, Arena);
}
}
SymbolSlab SymbolSlab::Builder::build() && {
Symbols = {Symbols.begin(), Symbols.end()}; // Force shrink-to-fit.
// Sort symbols so the slab can binary search over them.
std::sort(Symbols.begin(), Symbols.end(),
[](const Symbol &L, const Symbol &R) { return L.ID < R.ID; });
// We may have unused strings from overwritten symbols. Build a new arena.
BumpPtrAllocator NewArena;
DenseSet<StringRef> Strings;
for (auto &S : Symbols)
own(S, Strings, NewArena);
return SymbolSlab(std::move(NewArena), std::move(Symbols));
}
} // namespace clangd
} // namespace clang
|