164 lines · cpp
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-exception6//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 14namespace clang {15namespace clangd {16 17Symbol 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 31static 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.40Symbol 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@ns52 }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 62Symbol func(llvm::StringRef Name) { // Assumes the function has no args.63 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args64}65 66Symbol cls(llvm::StringRef Name) {67 return sym(Name, index::SymbolKind::Class, "@S@\\0");68}69 70Symbol enm(llvm::StringRef Name) {71 return sym(Name, index::SymbolKind::Enum, "@E@\\0");72}73 74Symbol enmConstant(llvm::StringRef Name) {75 return sym(Name, index::SymbolKind::EnumConstant, "@\\0");76}77 78Symbol var(llvm::StringRef Name) {79 return sym(Name, index::SymbolKind::Variable, "@\\0");80}81 82Symbol ns(llvm::StringRef Name) {83 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");84}85 86Symbol conceptSym(llvm::StringRef Name) {87 return sym(Name, index::SymbolKind::Concept, "@CT@\\0");88}89 90Symbol macro(llvm::StringRef Name, llvm::StringRef ArgList) {91 return sym(Name, index::SymbolKind::Macro, "@macro@\\0", ArgList);92}93 94Symbol 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 108Symbol objcClass(llvm::StringRef Name) {109 return objcSym(Name, index::SymbolKind::Class, "objc(cs)");110}111 112Symbol 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 117Symbol objcProtocol(llvm::StringRef Name) {118 return objcSym(Name, index::SymbolKind::Protocol, "objc(pl)");119}120 121SymbolSlab 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 128SymbolSlab 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 135std::string getQualifiedName(const Symbol &Sym) {136 return (Sym.Scope + Sym.Name + Sym.TemplateSpecializationArgs).str();137}138 139std::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.151std::vector<std::string> lookup(const SymbolIndex &I,152 llvm::ArrayRef<SymbolID> IDs) {153 LookupRequest Req;154 Req.IDs.insert_range(IDs);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 clangd163} // namespace clang164