1 | //===-- TestIndex.cpp -------------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "TestIndex.h" |
10 | #include "clang/Index/IndexSymbol.h" |
11 | #include "llvm/ADT/StringExtras.h" |
12 | #include "llvm/Support/Regex.h" |
13 | |
14 | namespace clang { |
15 | namespace clangd { |
16 | |
17 | Symbol symbol(llvm::StringRef QName) { |
18 | Symbol Sym; |
19 | Sym.ID = SymbolID(QName.str()); |
20 | size_t Pos = QName.rfind(Str: "::" ); |
21 | if (Pos == llvm::StringRef::npos) { |
22 | Sym.Name = QName; |
23 | Sym.Scope = "" ; |
24 | } else { |
25 | Sym.Name = QName.substr(Start: Pos + 2); |
26 | Sym.Scope = QName.substr(Start: 0, N: Pos + 2); |
27 | } |
28 | return Sym; |
29 | } |
30 | |
31 | static std::string replace(llvm::StringRef Haystack, llvm::StringRef Needle, |
32 | llvm::StringRef Repl) { |
33 | llvm::SmallVector<llvm::StringRef> Parts; |
34 | Haystack.split(A&: Parts, Separator: Needle); |
35 | return llvm::join(R&: Parts, Separator: Repl); |
36 | } |
37 | |
38 | // Helpers to produce fake index symbols for memIndex() or completions(). |
39 | // USRFormat is a regex replacement string for the unqualified part of the USR. |
40 | Symbol sym(llvm::StringRef QName, index::SymbolKind Kind, |
41 | llvm::StringRef USRFormat, llvm::StringRef Signature) { |
42 | Symbol Sym; |
43 | std::string USR = "c:" ; // We synthesize a few simple cases of USRs by hand! |
44 | size_t Pos = QName.rfind(Str: "::" ); |
45 | if (Pos == llvm::StringRef::npos) { |
46 | Sym.Name = QName; |
47 | Sym.Scope = "" ; |
48 | } else { |
49 | Sym.Name = QName.substr(Start: Pos + 2); |
50 | Sym.Scope = QName.substr(Start: 0, N: Pos + 2); |
51 | USR += "@N@" + replace(Haystack: QName.substr(Start: 0, N: Pos), Needle: "::" , Repl: "@N@" ); // ns:: -> @N@ns |
52 | } |
53 | USR += llvm::Regex("^.*$" ).sub(Repl: USRFormat, String: Sym.Name); // e.g. func -> @F@func# |
54 | Sym.ID = SymbolID(USR); |
55 | Sym.SymInfo.Kind = Kind; |
56 | Sym.Flags |= Symbol::IndexedForCodeCompletion; |
57 | Sym.Origin = SymbolOrigin::Static; |
58 | Sym.Signature = Signature; |
59 | return Sym; |
60 | } |
61 | |
62 | Symbol func(llvm::StringRef Name) { // Assumes the function has no args. |
63 | return sym(QName: Name, Kind: index::SymbolKind::Function, USRFormat: "@F@\\0#" ); // no args |
64 | } |
65 | |
66 | Symbol cls(llvm::StringRef Name) { |
67 | return sym(QName: Name, Kind: index::SymbolKind::Class, USRFormat: "@S@\\0" ); |
68 | } |
69 | |
70 | Symbol enm(llvm::StringRef Name) { |
71 | return sym(QName: Name, Kind: index::SymbolKind::Enum, USRFormat: "@E@\\0" ); |
72 | } |
73 | |
74 | Symbol enmConstant(llvm::StringRef Name) { |
75 | return sym(QName: Name, Kind: index::SymbolKind::EnumConstant, USRFormat: "@\\0" ); |
76 | } |
77 | |
78 | Symbol var(llvm::StringRef Name) { |
79 | return sym(QName: Name, Kind: index::SymbolKind::Variable, USRFormat: "@\\0" ); |
80 | } |
81 | |
82 | Symbol ns(llvm::StringRef Name) { |
83 | return sym(QName: Name, Kind: index::SymbolKind::Namespace, USRFormat: "@N@\\0" ); |
84 | } |
85 | |
86 | Symbol conceptSym(llvm::StringRef Name) { |
87 | return sym(QName: Name, Kind: index::SymbolKind::Concept, USRFormat: "@CT@\\0" ); |
88 | } |
89 | |
90 | Symbol macro(llvm::StringRef Name, llvm::StringRef ArgList) { |
91 | return sym(QName: Name, Kind: index::SymbolKind::Macro, USRFormat: "@macro@\\0" , Signature: ArgList); |
92 | } |
93 | |
94 | Symbol objcSym(llvm::StringRef Name, index::SymbolKind Kind, |
95 | llvm::StringRef USRPrefix) { |
96 | Symbol Sym; |
97 | std::string USR = USRPrefix.str() + Name.str(); |
98 | Sym.Name = Name; |
99 | Sym.Scope = "" ; |
100 | Sym.ID = SymbolID(USR); |
101 | Sym.SymInfo.Kind = Kind; |
102 | Sym.SymInfo.Lang = index::SymbolLanguage::ObjC; |
103 | Sym.Flags |= Symbol::IndexedForCodeCompletion; |
104 | Sym.Origin = SymbolOrigin::Static; |
105 | return Sym; |
106 | } |
107 | |
108 | Symbol objcClass(llvm::StringRef Name) { |
109 | return objcSym(Name, Kind: index::SymbolKind::Class, USRPrefix: "objc(cs)" ); |
110 | } |
111 | |
112 | Symbol objcCategory(llvm::StringRef Name, llvm::StringRef CategoryName) { |
113 | std::string USRPrefix = ("objc(cy)" + Name + "@" ).str(); |
114 | return objcSym(Name: CategoryName, Kind: index::SymbolKind::Extension, USRPrefix); |
115 | } |
116 | |
117 | Symbol objcProtocol(llvm::StringRef Name) { |
118 | return objcSym(Name, Kind: index::SymbolKind::Protocol, USRPrefix: "objc(pl)" ); |
119 | } |
120 | |
121 | SymbolSlab generateSymbols(std::vector<std::string> QualifiedNames) { |
122 | SymbolSlab::Builder Slab; |
123 | for (llvm::StringRef QName : QualifiedNames) |
124 | Slab.insert(S: symbol(QName)); |
125 | return std::move(Slab).build(); |
126 | } |
127 | |
128 | SymbolSlab generateNumSymbols(int Begin, int End) { |
129 | std::vector<std::string> Names; |
130 | for (int I = Begin; I <= End; I++) |
131 | Names.push_back(x: std::to_string(val: I)); |
132 | return generateSymbols(QualifiedNames: Names); |
133 | } |
134 | |
135 | std::string getQualifiedName(const Symbol &Sym) { |
136 | return (Sym.Scope + Sym.Name + Sym.TemplateSpecializationArgs).str(); |
137 | } |
138 | |
139 | std::vector<std::string> match(const SymbolIndex &I, |
140 | const FuzzyFindRequest &Req, bool *Incomplete) { |
141 | std::vector<std::string> Matches; |
142 | bool IsIncomplete = I.fuzzyFind(Req, Callback: [&](const Symbol &Sym) { |
143 | Matches.push_back(x: clang::clangd::getQualifiedName(Sym)); |
144 | }); |
145 | if (Incomplete) |
146 | *Incomplete = IsIncomplete; |
147 | return Matches; |
148 | } |
149 | |
150 | // Returns qualified names of symbols with any of IDs in the index. |
151 | std::vector<std::string> lookup(const SymbolIndex &I, |
152 | llvm::ArrayRef<SymbolID> IDs) { |
153 | LookupRequest Req; |
154 | Req.IDs.insert(I: IDs.begin(), E: IDs.end()); |
155 | std::vector<std::string> Results; |
156 | I.lookup(Req, Callback: [&](const Symbol &Sym) { |
157 | Results.push_back(x: getQualifiedName(Sym)); |
158 | }); |
159 | return Results; |
160 | } |
161 | |
162 | } // namespace clangd |
163 | } // namespace clang |
164 | |