xref: /llvm-project/clang-tools-extra/clangd/unittests/TestIndex.cpp (revision 7aa371687ace40b85f04e21956e03f1e93052b56)
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 
symbol(llvm::StringRef QName)17 Symbol symbol(llvm::StringRef QName) {
18   Symbol Sym;
19   Sym.ID = SymbolID(QName.str());
20   size_t Pos = QName.rfind("::");
21   if (Pos == llvm::StringRef::npos) {
22     Sym.Name = QName;
23     Sym.Scope = "";
24   } else {
25     Sym.Name = QName.substr(Pos + 2);
26     Sym.Scope = QName.substr(0, Pos + 2);
27   }
28   return Sym;
29 }
30 
replace(llvm::StringRef Haystack,llvm::StringRef Needle,llvm::StringRef Repl)31 static std::string replace(llvm::StringRef Haystack, llvm::StringRef Needle,
32                            llvm::StringRef Repl) {
33   llvm::SmallVector<llvm::StringRef> Parts;
34   Haystack.split(Parts, Needle);
35   return llvm::join(Parts, 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.
sym(llvm::StringRef QName,index::SymbolKind Kind,llvm::StringRef USRFormat,llvm::StringRef Signature)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("::");
45   if (Pos == llvm::StringRef::npos) {
46     Sym.Name = QName;
47     Sym.Scope = "";
48   } else {
49     Sym.Name = QName.substr(Pos + 2);
50     Sym.Scope = QName.substr(0, Pos + 2);
51     USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
52   }
53   USR += llvm::Regex("^.*$").sub(USRFormat, 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 
func(llvm::StringRef Name)62 Symbol func(llvm::StringRef Name) { // Assumes the function has no args.
63   return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
64 }
65 
cls(llvm::StringRef Name)66 Symbol cls(llvm::StringRef Name) {
67   return sym(Name, index::SymbolKind::Class, "@S@\\0");
68 }
69 
enm(llvm::StringRef Name)70 Symbol enm(llvm::StringRef Name) {
71   return sym(Name, index::SymbolKind::Enum, "@E@\\0");
72 }
73 
enmConstant(llvm::StringRef Name)74 Symbol enmConstant(llvm::StringRef Name) {
75   return sym(Name, index::SymbolKind::EnumConstant, "@\\0");
76 }
77 
var(llvm::StringRef Name)78 Symbol var(llvm::StringRef Name) {
79   return sym(Name, index::SymbolKind::Variable, "@\\0");
80 }
81 
ns(llvm::StringRef Name)82 Symbol ns(llvm::StringRef Name) {
83   return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
84 }
85 
conceptSym(llvm::StringRef Name)86 Symbol conceptSym(llvm::StringRef Name) {
87   return sym(Name, index::SymbolKind::Concept, "@CT@\\0");
88 }
89 
macro(llvm::StringRef Name,llvm::StringRef ArgList)90 Symbol macro(llvm::StringRef Name, llvm::StringRef ArgList) {
91   return sym(Name, index::SymbolKind::Macro, "@macro@\\0", ArgList);
92 }
93 
objcSym(llvm::StringRef Name,index::SymbolKind Kind,llvm::StringRef USRPrefix)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 
objcClass(llvm::StringRef Name)108 Symbol objcClass(llvm::StringRef Name) {
109   return objcSym(Name, index::SymbolKind::Class, "objc(cs)");
110 }
111 
objcCategory(llvm::StringRef Name,llvm::StringRef CategoryName)112 Symbol objcCategory(llvm::StringRef Name, llvm::StringRef CategoryName) {
113   std::string USRPrefix = ("objc(cy)" + Name + "@").str();
114   return objcSym(CategoryName, index::SymbolKind::Extension, USRPrefix);
115 }
116 
objcProtocol(llvm::StringRef Name)117 Symbol objcProtocol(llvm::StringRef Name) {
118   return objcSym(Name, index::SymbolKind::Protocol, "objc(pl)");
119 }
120 
generateSymbols(std::vector<std::string> QualifiedNames)121 SymbolSlab generateSymbols(std::vector<std::string> QualifiedNames) {
122   SymbolSlab::Builder Slab;
123   for (llvm::StringRef QName : QualifiedNames)
124     Slab.insert(symbol(QName));
125   return std::move(Slab).build();
126 }
127 
generateNumSymbols(int Begin,int End)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(std::to_string(I));
132   return generateSymbols(Names);
133 }
134 
getQualifiedName(const Symbol & Sym)135 std::string getQualifiedName(const Symbol &Sym) {
136   return (Sym.Scope + Sym.Name + Sym.TemplateSpecializationArgs).str();
137 }
138 
match(const SymbolIndex & I,const FuzzyFindRequest & Req,bool * Incomplete)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, [&](const Symbol &Sym) {
143     Matches.push_back(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.
lookup(const SymbolIndex & I,llvm::ArrayRef<SymbolID> IDs)151 std::vector<std::string> lookup(const SymbolIndex &I,
152                                 llvm::ArrayRef<SymbolID> IDs) {
153   LookupRequest Req;
154   Req.IDs.insert(IDs.begin(), IDs.end());
155   std::vector<std::string> Results;
156   I.lookup(Req, [&](const Symbol &Sym) {
157     Results.push_back(getQualifiedName(Sym));
158   });
159   return Results;
160 }
161 
162 } // namespace clangd
163 } // namespace clang
164