| 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_range(R&: IDs); |
| 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 | |