[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
//===--- FindSymbols.cpp ------------------------------------*- C++-*------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "FindSymbols.h"
|
|
|
|
|
2018-07-06 03:35:01 +08:00
|
|
|
#include "AST.h"
|
|
|
|
#include "ClangdUnit.h"
|
2018-06-07 14:55:59 +08:00
|
|
|
#include "FuzzyMatch.h"
|
2018-07-06 03:35:01 +08:00
|
|
|
#include "Logger.h"
|
2018-06-07 14:55:59 +08:00
|
|
|
#include "Quality.h"
|
2018-07-06 03:35:01 +08:00
|
|
|
#include "SourceCode.h"
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
#include "index/Index.h"
|
2018-11-23 23:21:19 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2018-07-06 03:35:01 +08:00
|
|
|
#include "clang/Index/IndexDataConsumer.h"
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
#include "clang/Index/IndexSymbol.h"
|
2018-07-06 03:35:01 +08:00
|
|
|
#include "clang/Index/IndexingAction.h"
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2018-11-23 23:21:19 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
|
2018-06-07 14:55:59 +08:00
|
|
|
#define DEBUG_TYPE "FindSymbols"
|
|
|
|
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
|
[clangd] Add support for type hierarchy (super types only for now)
Summary:
Patch by Nathan Ridge(@nridge)!
This is an LSP extension proposed here:
https://github.com/Microsoft/vscode-languageserver-node/pull/426
An example client implementation can be found here:
https://github.com/theia-ide/theia/pull/3802
Reviewers: kadircet, sammccall
Reviewed By: kadircet
Subscribers: jdoerfert, sammccall, cfe-commits, mgorny, dschaefer, simark, ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, kadircet
Tags: #clang
Differential Revision: https://reviews.llvm.org/D56370
llvm-svn: 356445
2019-03-19 17:27:04 +08:00
|
|
|
namespace {
|
2018-06-07 14:55:59 +08:00
|
|
|
using ScoredSymbolInfo = std::pair<float, SymbolInformation>;
|
|
|
|
struct ScoredSymbolGreater {
|
|
|
|
bool operator()(const ScoredSymbolInfo &L, const ScoredSymbolInfo &R) {
|
|
|
|
if (L.first != R.first)
|
|
|
|
return L.first > R.first;
|
|
|
|
return L.second.name < R.second.name; // Earlier name is better.
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
} // namespace
|
|
|
|
|
[clangd] Type hierarchy subtypes
Summary:
This builds on the relations support added in D59407, D62459, D62471,
and D62839 to implement type hierarchy subtypes.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, mgrang, arphaman,
jdoerfert, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D58880
llvm-svn: 363506
2019-06-16 10:31:37 +08:00
|
|
|
llvm::Expected<Location> symbolToLocation(const Symbol &Sym,
|
|
|
|
llvm::StringRef HintPath) {
|
|
|
|
// Prefer the definition over e.g. a function declaration in a header
|
|
|
|
auto &CD = Sym.Definition ? Sym.Definition : Sym.CanonicalDeclaration;
|
|
|
|
auto Uri = URI::parse(CD.FileURI);
|
|
|
|
if (!Uri) {
|
|
|
|
return llvm::make_error<llvm::StringError>(
|
|
|
|
formatv("Could not parse URI '{0}' for symbol '{1}'.", CD.FileURI,
|
|
|
|
Sym.Name),
|
|
|
|
llvm::inconvertibleErrorCode());
|
|
|
|
}
|
|
|
|
auto Path = URI::resolve(*Uri, HintPath);
|
|
|
|
if (!Path) {
|
|
|
|
return llvm::make_error<llvm::StringError>(
|
|
|
|
formatv("Could not resolve path for URI '{0}' for symbol '{1}'.",
|
|
|
|
Uri->toString(), Sym.Name),
|
|
|
|
llvm::inconvertibleErrorCode());
|
|
|
|
}
|
|
|
|
Location L;
|
|
|
|
// Use HintPath as TUPath since there is no TU associated with this
|
|
|
|
// request.
|
|
|
|
L.uri = URIForFile::canonicalize(*Path, HintPath);
|
|
|
|
Position Start, End;
|
|
|
|
Start.line = CD.Start.line();
|
|
|
|
Start.character = CD.Start.column();
|
|
|
|
End.line = CD.End.line();
|
|
|
|
End.character = CD.End.column();
|
|
|
|
L.range = {Start, End};
|
|
|
|
return L;
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Expected<std::vector<SymbolInformation>>
|
|
|
|
getWorkspaceSymbols(llvm::StringRef Query, int Limit,
|
|
|
|
const SymbolIndex *const Index, llvm::StringRef HintPath) {
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
std::vector<SymbolInformation> Result;
|
|
|
|
if (Query.empty() || !Index)
|
|
|
|
return Result;
|
|
|
|
|
|
|
|
auto Names = splitQualifiedName(Query);
|
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = Names.second;
|
|
|
|
|
|
|
|
// FuzzyFind doesn't want leading :: qualifier
|
|
|
|
bool IsGlobalQuery = Names.first.consume_front("::");
|
|
|
|
// Restrict results to the scope in the query string if present (global or
|
|
|
|
// not).
|
|
|
|
if (IsGlobalQuery || !Names.first.empty())
|
|
|
|
Req.Scopes = {Names.first};
|
2018-11-06 19:08:17 +08:00
|
|
|
else
|
|
|
|
Req.AnyScope = true;
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
if (Limit)
|
2018-09-13 22:27:03 +08:00
|
|
|
Req.Limit = Limit;
|
|
|
|
TopN<ScoredSymbolInfo, ScoredSymbolGreater> Top(
|
|
|
|
Req.Limit ? *Req.Limit : std::numeric_limits<size_t>::max());
|
2018-06-07 14:55:59 +08:00
|
|
|
FuzzyMatcher Filter(Req.Query);
|
2018-06-19 17:33:53 +08:00
|
|
|
Index->fuzzyFind(Req, [HintPath, &Top, &Filter](const Symbol &Sym) {
|
[clangd] Type hierarchy subtypes
Summary:
This builds on the relations support added in D59407, D62459, D62471,
and D62839 to implement type hierarchy subtypes.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, mgrang, arphaman,
jdoerfert, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D58880
llvm-svn: 363506
2019-06-16 10:31:37 +08:00
|
|
|
auto Loc = symbolToLocation(Sym, HintPath);
|
|
|
|
if (!Loc) {
|
|
|
|
log("Workspace symbols: {0}", Loc.takeError());
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
return;
|
|
|
|
}
|
[clangd] Type hierarchy subtypes
Summary:
This builds on the relations support added in D59407, D62459, D62471,
and D62839 to implement type hierarchy subtypes.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, mgrang, arphaman,
jdoerfert, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D58880
llvm-svn: 363506
2019-06-16 10:31:37 +08:00
|
|
|
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
SymbolKind SK = indexSymbolKindToSymbolKind(Sym.SymInfo.Kind);
|
|
|
|
std::string Scope = Sym.Scope;
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::StringRef ScopeRef = Scope;
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
ScopeRef.consume_back("::");
|
2019-04-12 18:09:37 +08:00
|
|
|
SymbolInformation Info = {(Sym.Name + Sym.TemplateSpecializationArgs).str(),
|
[clangd] Type hierarchy subtypes
Summary:
This builds on the relations support added in D59407, D62459, D62471,
and D62839 to implement type hierarchy subtypes.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, mgrang, arphaman,
jdoerfert, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D58880
llvm-svn: 363506
2019-06-16 10:31:37 +08:00
|
|
|
SK, *Loc, ScopeRef};
|
2018-06-07 14:55:59 +08:00
|
|
|
|
|
|
|
SymbolQualitySignals Quality;
|
|
|
|
Quality.merge(Sym);
|
|
|
|
SymbolRelevanceSignals Relevance;
|
2019-05-06 18:25:10 +08:00
|
|
|
Relevance.Name = Sym.Name;
|
2018-06-07 14:55:59 +08:00
|
|
|
Relevance.Query = SymbolRelevanceSignals::Generic;
|
|
|
|
if (auto NameMatch = Filter.match(Sym.Name))
|
|
|
|
Relevance.NameMatch = *NameMatch;
|
|
|
|
else {
|
[clangd] Upgrade logging facilities with levels and formatv.
Summary:
log() is split into four functions:
- elog()/log()/vlog() have different severity levels, allowing filtering
- dlog() is a lazy macro which uses LLVM_DEBUG - it logs to the logger, but
conditionally based on -debug-only flag and is omitted in release builds
All logging functions use formatv-style format strings now, e.g:
log("Could not resolve URI {0}: {1}", URI, Result.takeError());
Existing log sites have been split between elog/log/vlog by best guess.
This includes a workaround for passing Error to formatv that can be
simplified when D49170 or similar lands.
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D49008
llvm-svn: 336785
2018-07-11 18:35:11 +08:00
|
|
|
log("Workspace symbol: {0} didn't match query {1}", Sym.Name,
|
|
|
|
Filter.pattern());
|
2018-06-07 14:55:59 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
Relevance.merge(Sym);
|
|
|
|
auto Score =
|
|
|
|
evaluateSymbolAndRelevance(Quality.evaluate(), Relevance.evaluate());
|
[clangd] Upgrade logging facilities with levels and formatv.
Summary:
log() is split into four functions:
- elog()/log()/vlog() have different severity levels, allowing filtering
- dlog() is a lazy macro which uses LLVM_DEBUG - it logs to the logger, but
conditionally based on -debug-only flag and is omitted in release builds
All logging functions use formatv-style format strings now, e.g:
log("Could not resolve URI {0}: {1}", URI, Result.takeError());
Existing log sites have been split between elog/log/vlog by best guess.
This includes a workaround for passing Error to formatv that can be
simplified when D49170 or similar lands.
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D49008
llvm-svn: 336785
2018-07-11 18:35:11 +08:00
|
|
|
dlog("FindSymbols: {0}{1} = {2}\n{3}{4}\n", Sym.Scope, Sym.Name, Score,
|
|
|
|
Quality, Relevance);
|
2018-06-07 14:55:59 +08:00
|
|
|
|
|
|
|
Top.push({Score, std::move(Info)});
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
});
|
2018-06-07 14:55:59 +08:00
|
|
|
for (auto &R : std::move(Top).items())
|
|
|
|
Result.push_back(std::move(R.second));
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-07-06 03:35:01 +08:00
|
|
|
namespace {
|
2018-11-23 23:21:19 +08:00
|
|
|
llvm::Optional<DocumentSymbol> declToSym(ASTContext &Ctx, const NamedDecl &ND) {
|
|
|
|
auto &SM = Ctx.getSourceManager();
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2019-08-07 04:25:59 +08:00
|
|
|
SourceLocation NameLoc = spellingLocIfSpelled(findName(&ND), SM);
|
2018-11-23 23:21:19 +08:00
|
|
|
// getFileLoc is a good choice for us, but we also need to make sure
|
|
|
|
// sourceLocToPosition won't switch files, so we call getSpellingLoc on top of
|
|
|
|
// that to make sure it does not switch files.
|
|
|
|
// FIXME: sourceLocToPosition should not switch files!
|
2019-01-03 21:28:05 +08:00
|
|
|
SourceLocation BeginLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc()));
|
2018-11-23 23:21:19 +08:00
|
|
|
SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc()));
|
|
|
|
if (NameLoc.isInvalid() || BeginLoc.isInvalid() || EndLoc.isInvalid())
|
|
|
|
return llvm::None;
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
if (!SM.isWrittenInMainFile(NameLoc) || !SM.isWrittenInMainFile(BeginLoc) ||
|
|
|
|
!SM.isWrittenInMainFile(EndLoc))
|
|
|
|
return llvm::None;
|
|
|
|
|
|
|
|
Position NameBegin = sourceLocToPosition(SM, NameLoc);
|
|
|
|
Position NameEnd = sourceLocToPosition(
|
|
|
|
SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));
|
|
|
|
|
|
|
|
index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
|
|
|
|
// FIXME: this is not classifying constructors, destructors and operators
|
|
|
|
// correctly (they're all "methods").
|
|
|
|
SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
|
|
|
|
|
|
|
|
DocumentSymbol SI;
|
|
|
|
SI.name = printName(Ctx, ND);
|
|
|
|
SI.kind = SK;
|
|
|
|
SI.deprecated = ND.isDeprecated();
|
|
|
|
SI.range =
|
|
|
|
Range{sourceLocToPosition(SM, BeginLoc), sourceLocToPosition(SM, EndLoc)};
|
|
|
|
SI.selectionRange = Range{NameBegin, NameEnd};
|
|
|
|
if (!SI.range.contains(SI.selectionRange)) {
|
|
|
|
// 'selectionRange' must be contained in 'range', so in cases where clang
|
|
|
|
// reports unrelated ranges we need to reconcile somehow.
|
|
|
|
SI.range = SI.selectionRange;
|
2018-07-06 03:35:01 +08:00
|
|
|
}
|
2018-11-23 23:21:19 +08:00
|
|
|
return SI;
|
|
|
|
}
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2019-08-14 18:49:32 +08:00
|
|
|
/// A helper class to build an outline for the parse AST. It traverses the AST
|
2018-11-23 23:21:19 +08:00
|
|
|
/// directly instead of using RecursiveASTVisitor (RAV) for three main reasons:
|
2019-08-14 18:49:32 +08:00
|
|
|
/// - there is no way to keep RAV from traversing subtrees we are not
|
2018-11-23 23:21:19 +08:00
|
|
|
/// interested in. E.g. not traversing function locals or implicit template
|
|
|
|
/// instantiations.
|
2019-08-14 18:49:32 +08:00
|
|
|
/// - it's easier to combine results of recursive passes,
|
2018-11-23 23:21:19 +08:00
|
|
|
/// - visiting decls is actually simple, so we don't hit the complicated
|
2019-08-14 18:49:32 +08:00
|
|
|
/// cases that RAV mostly helps with (types, expressions, etc.)
|
2018-11-23 23:21:19 +08:00
|
|
|
class DocumentOutline {
|
|
|
|
public:
|
|
|
|
DocumentOutline(ParsedAST &AST) : AST(AST) {}
|
|
|
|
|
|
|
|
/// Builds the document outline for the generated AST.
|
|
|
|
std::vector<DocumentSymbol> build() {
|
|
|
|
std::vector<DocumentSymbol> Results;
|
|
|
|
for (auto &TopLevel : AST.getLocalTopLevelDecls())
|
|
|
|
traverseDecl(TopLevel, Results);
|
|
|
|
return Results;
|
2018-07-06 03:35:01 +08:00
|
|
|
}
|
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
private:
|
|
|
|
enum class VisitKind { No, OnlyDecl, DeclAndChildren };
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
void traverseDecl(Decl *D, std::vector<DocumentSymbol> &Results) {
|
|
|
|
if (auto *Templ = llvm::dyn_cast<TemplateDecl>(D))
|
|
|
|
D = Templ->getTemplatedDecl();
|
|
|
|
auto *ND = llvm::dyn_cast<NamedDecl>(D);
|
|
|
|
if (!ND)
|
|
|
|
return;
|
|
|
|
VisitKind Visit = shouldVisit(ND);
|
|
|
|
if (Visit == VisitKind::No)
|
|
|
|
return;
|
|
|
|
llvm::Optional<DocumentSymbol> Sym = declToSym(AST.getASTContext(), *ND);
|
|
|
|
if (!Sym)
|
|
|
|
return;
|
|
|
|
if (Visit == VisitKind::DeclAndChildren)
|
|
|
|
traverseChildren(D, Sym->children);
|
|
|
|
Results.push_back(std::move(*Sym));
|
|
|
|
}
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
void traverseChildren(Decl *D, std::vector<DocumentSymbol> &Results) {
|
|
|
|
auto *Scope = llvm::dyn_cast<DeclContext>(D);
|
|
|
|
if (!Scope)
|
|
|
|
return;
|
|
|
|
for (auto *C : Scope->decls())
|
|
|
|
traverseDecl(C, Results);
|
|
|
|
}
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
VisitKind shouldVisit(NamedDecl *D) {
|
|
|
|
if (D->isImplicit())
|
|
|
|
return VisitKind::No;
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
if (auto Func = llvm::dyn_cast<FunctionDecl>(D)) {
|
|
|
|
// Some functions are implicit template instantiations, those should be
|
|
|
|
// ignored.
|
|
|
|
if (auto *Info = Func->getTemplateSpecializationInfo()) {
|
|
|
|
if (!Info->isExplicitInstantiationOrSpecialization())
|
|
|
|
return VisitKind::No;
|
|
|
|
}
|
|
|
|
// Only visit the function itself, do not visit the children (i.e.
|
|
|
|
// function parameters, etc.)
|
|
|
|
return VisitKind::OnlyDecl;
|
|
|
|
}
|
|
|
|
// Handle template instantiations. We have three cases to consider:
|
|
|
|
// - explicit instantiations, e.g. 'template class std::vector<int>;'
|
|
|
|
// Visit the decl itself (it's present in the code), but not the
|
|
|
|
// children.
|
|
|
|
// - implicit instantiations, i.e. not written by the user.
|
|
|
|
// Do not visit at all, they are not present in the code.
|
|
|
|
// - explicit specialization, e.g. 'template <> class vector<bool> {};'
|
|
|
|
// Visit both the decl and its children, both are written in the code.
|
|
|
|
if (auto *TemplSpec = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) {
|
|
|
|
if (TemplSpec->isExplicitInstantiationOrSpecialization())
|
|
|
|
return TemplSpec->isExplicitSpecialization()
|
|
|
|
? VisitKind::DeclAndChildren
|
|
|
|
: VisitKind::OnlyDecl;
|
|
|
|
return VisitKind::No;
|
|
|
|
}
|
|
|
|
if (auto *TemplSpec = llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) {
|
|
|
|
if (TemplSpec->isExplicitInstantiationOrSpecialization())
|
|
|
|
return TemplSpec->isExplicitSpecialization()
|
|
|
|
? VisitKind::DeclAndChildren
|
|
|
|
: VisitKind::OnlyDecl;
|
|
|
|
return VisitKind::No;
|
|
|
|
}
|
|
|
|
// For all other cases, visit both the children and the decl.
|
|
|
|
return VisitKind::DeclAndChildren;
|
2018-07-06 03:35:01 +08:00
|
|
|
}
|
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
ParsedAST &AST;
|
|
|
|
};
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
std::vector<DocumentSymbol> collectDocSymbols(ParsedAST &AST) {
|
|
|
|
return DocumentOutline(AST).build();
|
|
|
|
}
|
|
|
|
} // namespace
|
2018-07-06 03:35:01 +08:00
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
llvm::Expected<std::vector<DocumentSymbol>> getDocumentSymbols(ParsedAST &AST) {
|
|
|
|
return collectDocSymbols(AST);
|
2018-07-06 03:35:01 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|