17 #include "clang/AST/DeclTemplate.h"
18 #include "clang/Index/IndexDataConsumer.h"
19 #include "clang/Index/IndexSymbol.h"
20 #include "clang/Index/IndexingAction.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/FormatVariadic.h"
23 #include "llvm/Support/Path.h"
24 #include "llvm/Support/ScopedPrinter.h"
26 #define DEBUG_TYPE "FindSymbols"
32 using ScoredSymbolInfo = std::pair<float, SymbolInformation>;
33 struct ScoredSymbolGreater {
34 bool operator()(
const ScoredSymbolInfo &L,
const ScoredSymbolInfo &R) {
35 if (L.first != R.first)
36 return L.first > R.first;
37 return L.second.name < R.second.name;
44 llvm::StringRef TUPath) {
47 return llvm::make_error<llvm::StringError>(
48 llvm::formatv(
"Could not resolve path for file '{0}': {1}",
Loc.FileURI,
50 llvm::inconvertibleErrorCode());
55 Start.line =
Loc.Start.line();
56 Start.character =
Loc.Start.column();
57 End.line =
Loc.End.line();
58 End.character =
Loc.End.column();
59 L.
range = {Start, End};
64 llvm::StringRef TUPath) {
70 llvm::Expected<std::vector<SymbolInformation>>
73 std::vector<SymbolInformation> Result;
74 if (Query.empty() || !
Index)
80 Req.
Query = std::string(Names.second);
83 bool IsGlobalQuery = Names.first.consume_front(
"::");
86 if (IsGlobalQuery || !Names.first.empty())
87 Req.
Scopes = {std::string(Names.first)};
92 TopN<ScoredSymbolInfo, ScoredSymbolGreater> Top(
93 Req.Limit ? *Req.Limit : std::numeric_limits<size_t>::max());
94 FuzzyMatcher Filter(Req.Query);
95 Index->
fuzzyFind(Req, [HintPath, &Top, &Filter](
const Symbol &Sym) {
98 log(
"Workspace symbols: {0}",
Loc.takeError());
103 std::string Scope = std::string(Sym.Scope);
104 llvm::StringRef ScopeRef = Scope;
105 ScopeRef.consume_back(
"::");
106 SymbolInformation
Info = {(Sym.Name + Sym.TemplateSpecializationArgs).str(),
107 SK, *
Loc, std::string(ScopeRef)};
111 SymbolRelevanceSignals Relevance;
112 Relevance.Name = Sym.Name;
114 if (
auto NameMatch = Filter.match(Sym.Name))
115 Relevance.NameMatch = *NameMatch;
117 log(
"Workspace symbol: {0} didn't match query {1}", Sym.Name,
121 Relevance.merge(Sym);
124 dlog(
"FindSymbols: {0}{1} = {2}\n{3}{4}\n", Sym.Scope, Sym.Name,
Score,
127 Top.push({
Score, std::move(Info)});
129 for (
auto &R : std::move(Top).items())
130 Result.push_back(std::move(R.second));
135 llvm::Optional<DocumentSymbol> declToSym(ASTContext &
Ctx,
const NamedDecl &ND) {
136 auto &SM =
Ctx.getSourceManager();
139 SourceLocation BeginLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc()));
140 SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc()));
141 const auto SymbolRange =
148 SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM,
Ctx.getLangOpts()));
158 SI.deprecated = ND.isDeprecated();
161 SI.selectionRange =
Range{NameBegin, NameEnd};
162 if (!SI.range.contains(SI.selectionRange)) {
165 SI.range = SI.selectionRange;
178 class DocumentOutline {
180 DocumentOutline(ParsedAST &
AST) :
AST(
AST) {}
183 std::vector<DocumentSymbol> build() {
184 std::vector<DocumentSymbol>
Results;
185 for (
auto &TopLevel :
AST.getLocalTopLevelDecls())
186 traverseDecl(TopLevel,
Results);
191 enum class VisitKind {
No, OnlyDecl, DeclAndChildren };
193 void traverseDecl(
Decl *D, std::vector<DocumentSymbol> &
Results) {
194 if (
auto *Templ = llvm::dyn_cast<TemplateDecl>(D)) {
196 if (
auto *TD = Templ->getTemplatedDecl())
199 auto *ND = llvm::dyn_cast<NamedDecl>(D);
202 VisitKind Visit = shouldVisit(ND);
203 if (Visit == VisitKind::No)
205 llvm::Optional<DocumentSymbol> Sym = declToSym(
AST.getASTContext(), *ND);
208 if (Visit == VisitKind::DeclAndChildren)
209 traverseChildren(D, Sym->children);
210 Results.push_back(std::move(*Sym));
213 void traverseChildren(
Decl *D, std::vector<DocumentSymbol> &
Results) {
214 auto *Scope = llvm::dyn_cast<DeclContext>(D);
217 for (
auto *C : Scope->decls())
221 VisitKind shouldVisit(NamedDecl *D) {
223 return VisitKind::No;
225 if (
auto Func = llvm::dyn_cast<FunctionDecl>(D)) {
228 if (
auto *
Info = Func->getTemplateSpecializationInfo()) {
229 if (!
Info->isExplicitInstantiationOrSpecialization())
230 return VisitKind::No;
234 return VisitKind::OnlyDecl;
244 if (
auto *TemplSpec = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) {
245 if (TemplSpec->isExplicitInstantiationOrSpecialization())
246 return TemplSpec->isExplicitSpecialization()
247 ? VisitKind::DeclAndChildren
248 : VisitKind::OnlyDecl;
249 return VisitKind::No;
251 if (
auto *TemplSpec = llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) {
252 if (TemplSpec->isExplicitInstantiationOrSpecialization())
253 return TemplSpec->isExplicitSpecialization()
254 ? VisitKind::DeclAndChildren
255 : VisitKind::OnlyDecl;
256 return VisitKind::No;
259 return VisitKind::DeclAndChildren;
265 std::vector<DocumentSymbol> collectDocSymbols(ParsedAST &
AST) {
266 return DocumentOutline(
AST).build();
271 return collectDocSymbols(
AST);