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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
//===-- TestIndex.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
//
//===----------------------------------------------------------------------===//
#include "TestIndex.h"
#include "clang/Index/IndexSymbol.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Regex.h"
namespace clang {
namespace clangd {
Symbol symbol(llvm::StringRef QName) {
Symbol Sym;
Sym.ID = SymbolID(QName.str());
size_t Pos = QName.rfind("::");
if (Pos == llvm::StringRef::npos) {
Sym.Name = QName;
Sym.Scope = "";
} else {
Sym.Name = QName.substr(Pos + 2);
Sym.Scope = QName.substr(0, Pos + 2);
}
return Sym;
}
static std::string replace(llvm::StringRef Haystack, llvm::StringRef Needle,
llvm::StringRef Repl) {
llvm::SmallVector<llvm::StringRef> Parts;
Haystack.split(Parts, Needle);
return llvm::join(Parts, Repl);
}
// Helpers to produce fake index symbols for memIndex() or completions().
// USRFormat is a regex replacement string for the unqualified part of the USR.
Symbol sym(llvm::StringRef QName, index::SymbolKind Kind,
llvm::StringRef USRFormat, llvm::StringRef Signature) {
Symbol Sym;
std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
size_t Pos = QName.rfind("::");
if (Pos == llvm::StringRef::npos) {
Sym.Name = QName;
Sym.Scope = "";
} else {
Sym.Name = QName.substr(Pos + 2);
Sym.Scope = QName.substr(0, Pos + 2);
USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
}
USR += llvm::Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
Sym.ID = SymbolID(USR);
Sym.SymInfo.Kind = Kind;
Sym.Flags |= Symbol::IndexedForCodeCompletion;
Sym.Origin = SymbolOrigin::Static;
Sym.Signature = Signature;
return Sym;
}
Symbol func(llvm::StringRef Name) { // Assumes the function has no args.
return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
}
Symbol cls(llvm::StringRef Name) {
return sym(Name, index::SymbolKind::Class, "@S@\\0");
}
Symbol enm(llvm::StringRef Name) {
return sym(Name, index::SymbolKind::Enum, "@E@\\0");
}
Symbol enmConstant(llvm::StringRef Name) {
return sym(Name, index::SymbolKind::EnumConstant, "@\\0");
}
Symbol var(llvm::StringRef Name) {
return sym(Name, index::SymbolKind::Variable, "@\\0");
}
Symbol ns(llvm::StringRef Name) {
return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
}
Symbol conceptSym(llvm::StringRef Name) {
return sym(Name, index::SymbolKind::Concept, "@CT@\\0");
}
Symbol macro(llvm::StringRef Name, llvm::StringRef ArgList) {
return sym(Name, index::SymbolKind::Macro, "@macro@\\0", ArgList);
}
Symbol objcSym(llvm::StringRef Name, index::SymbolKind Kind,
llvm::StringRef USRPrefix) {
Symbol Sym;
std::string USR = USRPrefix.str() + Name.str();
Sym.Name = Name;
Sym.Scope = "";
Sym.ID = SymbolID(USR);
Sym.SymInfo.Kind = Kind;
Sym.SymInfo.Lang = index::SymbolLanguage::ObjC;
Sym.Flags |= Symbol::IndexedForCodeCompletion;
Sym.Origin = SymbolOrigin::Static;
return Sym;
}
Symbol objcClass(llvm::StringRef Name) {
return objcSym(Name, index::SymbolKind::Class, "objc(cs)");
}
Symbol objcCategory(llvm::StringRef Name, llvm::StringRef CategoryName) {
std::string USRPrefix = ("objc(cy)" + Name + "@").str();
return objcSym(CategoryName, index::SymbolKind::Extension, USRPrefix);
}
Symbol objcProtocol(llvm::StringRef Name) {
return objcSym(Name, index::SymbolKind::Protocol, "objc(pl)");
}
SymbolSlab generateSymbols(std::vector<std::string> QualifiedNames) {
SymbolSlab::Builder Slab;
for (llvm::StringRef QName : QualifiedNames)
Slab.insert(symbol(QName));
return std::move(Slab).build();
}
SymbolSlab generateNumSymbols(int Begin, int End) {
std::vector<std::string> Names;
for (int I = Begin; I <= End; I++)
Names.push_back(std::to_string(I));
return generateSymbols(Names);
}
std::string getQualifiedName(const Symbol &Sym) {
return (Sym.Scope + Sym.Name + Sym.TemplateSpecializationArgs).str();
}
std::vector<std::string> match(const SymbolIndex &I,
const FuzzyFindRequest &Req, bool *Incomplete) {
std::vector<std::string> Matches;
bool IsIncomplete = I.fuzzyFind(Req, [&](const Symbol &Sym) {
Matches.push_back(clang::clangd::getQualifiedName(Sym));
});
if (Incomplete)
*Incomplete = IsIncomplete;
return Matches;
}
// Returns qualified names of symbols with any of IDs in the index.
std::vector<std::string> lookup(const SymbolIndex &I,
llvm::ArrayRef<SymbolID> IDs) {
LookupRequest Req;
Req.IDs.insert_range(IDs);
std::vector<std::string> Results;
I.lookup(Req, [&](const Symbol &Sym) {
Results.push_back(getQualifiedName(Sym));
});
return Results;
}
} // namespace clangd
} // namespace clang
|