mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-24 08:35:08 +00:00
Support textDocument/declaration & LocationLink
textDocument/{declaration,definition,typeDefinition} return either LocationLink[] or Location[] Add an initialization option client.linkSupport . When it is false, ccls will return Location[] disregarding client's linkSupport. `struct LocationLink` does not include originSelectionRange as it is wasteful.
This commit is contained in:
parent
37a9ad3f81
commit
fc38442967
@ -85,6 +85,8 @@ struct Config {
|
|||||||
struct ClientCapability {
|
struct ClientCapability {
|
||||||
// TextDocumentClientCapabilities.documentSymbol.hierarchicalDocumentSymbolSupport
|
// TextDocumentClientCapabilities.documentSymbol.hierarchicalDocumentSymbolSupport
|
||||||
bool hierarchicalDocumentSymbolSupport = true;
|
bool hierarchicalDocumentSymbolSupport = true;
|
||||||
|
// TextDocumentClientCapabilities.definition.linkSupport
|
||||||
|
bool linkSupport = true;
|
||||||
// TextDocumentClientCapabilities.completion.completionItem.snippetSupport
|
// TextDocumentClientCapabilities.completion.completionItem.snippetSupport
|
||||||
bool snippetSupport = true;
|
bool snippetSupport = true;
|
||||||
} client;
|
} client;
|
||||||
@ -260,30 +262,28 @@ struct Config {
|
|||||||
} xref;
|
} xref;
|
||||||
};
|
};
|
||||||
REFLECT_STRUCT(Config::Clang, excludeArgs, extraArgs, pathMappings,
|
REFLECT_STRUCT(Config::Clang, excludeArgs, extraArgs, pathMappings,
|
||||||
resourceDir);
|
resourceDir);
|
||||||
REFLECT_STRUCT(Config::ClientCapability, hierarchicalDocumentSymbolSupport,
|
REFLECT_STRUCT(Config::ClientCapability, hierarchicalDocumentSymbolSupport,
|
||||||
snippetSupport);
|
linkSupport, snippetSupport);
|
||||||
REFLECT_STRUCT(Config::CodeLens, localVariables);
|
REFLECT_STRUCT(Config::CodeLens, localVariables);
|
||||||
REFLECT_STRUCT(Config::Completion::Include, blacklist, maxPathSize,
|
REFLECT_STRUCT(Config::Completion::Include, blacklist, maxPathSize,
|
||||||
suffixWhitelist, whitelist);
|
suffixWhitelist, whitelist);
|
||||||
REFLECT_STRUCT(Config::Completion, caseSensitivity, detailedLabel,
|
REFLECT_STRUCT(Config::Completion, caseSensitivity, detailedLabel,
|
||||||
dropOldRequests, duplicateOptional, filterAndSort, include,
|
dropOldRequests, duplicateOptional, filterAndSort, include,
|
||||||
maxNum);
|
maxNum);
|
||||||
REFLECT_STRUCT(Config::Diagnostics, blacklist, onChange, onOpen, onSave,
|
REFLECT_STRUCT(Config::Diagnostics, blacklist, onChange, onOpen, onSave,
|
||||||
spellChecking, whitelist)
|
spellChecking, whitelist)
|
||||||
REFLECT_STRUCT(Config::Highlight, largeFileSize, lsRanges, blacklist,
|
REFLECT_STRUCT(Config::Highlight, largeFileSize, lsRanges, blacklist, whitelist)
|
||||||
whitelist)
|
|
||||||
REFLECT_STRUCT(Config::Index, blacklist, comments, initialBlacklist,
|
REFLECT_STRUCT(Config::Index, blacklist, comments, initialBlacklist,
|
||||||
initialWhitelist, multiVersion, multiVersionBlacklist,
|
initialWhitelist, multiVersion, multiVersionBlacklist,
|
||||||
multiVersionWhitelist, onChange, threads, trackDependency,
|
multiVersionWhitelist, onChange, threads, trackDependency,
|
||||||
whitelist);
|
whitelist);
|
||||||
REFLECT_STRUCT(Config::Session, maxNum);
|
REFLECT_STRUCT(Config::Session, maxNum);
|
||||||
REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
|
REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
|
||||||
REFLECT_STRUCT(Config::Xref, maxNum);
|
REFLECT_STRUCT(Config::Xref, maxNum);
|
||||||
REFLECT_STRUCT(Config, compilationDatabaseCommand,
|
REFLECT_STRUCT(Config, compilationDatabaseCommand, compilationDatabaseDirectory,
|
||||||
compilationDatabaseDirectory, cacheDirectory, cacheFormat,
|
cacheDirectory, cacheFormat, clang, client, codeLens, completion,
|
||||||
clang, client, codeLens, completion, diagnostics, highlight,
|
diagnostics, highlight, index, session, workspaceSymbol, xref);
|
||||||
index, session, workspaceSymbol, xref);
|
|
||||||
|
|
||||||
extern Config *g_config;
|
extern Config *g_config;
|
||||||
|
|
||||||
|
@ -60,10 +60,6 @@ DocumentUri DocumentUri::FromPath(const std::string &path) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DocumentUri::operator==(const DocumentUri &other) const {
|
|
||||||
return raw_uri == other.raw_uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DocumentUri::SetPath(const std::string &path) {
|
void DocumentUri::SetPath(const std::string &path) {
|
||||||
// file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests
|
// file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests
|
||||||
raw_uri = path;
|
raw_uri = path;
|
||||||
|
25
src/lsp.hh
25
src/lsp.hh
@ -72,7 +72,8 @@ constexpr char window_showMessage[] = "window/showMessage";
|
|||||||
struct DocumentUri {
|
struct DocumentUri {
|
||||||
static DocumentUri FromPath(const std::string &path);
|
static DocumentUri FromPath(const std::string &path);
|
||||||
|
|
||||||
bool operator==(const DocumentUri &other) const;
|
bool operator==(const DocumentUri &o) const { return raw_uri == o.raw_uri; }
|
||||||
|
bool operator<(const DocumentUri &o) const { return raw_uri < o.raw_uri; }
|
||||||
|
|
||||||
void SetPath(const std::string &path);
|
void SetPath(const std::string &path);
|
||||||
std::string GetPath() const;
|
std::string GetPath() const;
|
||||||
@ -119,8 +120,26 @@ struct Location {
|
|||||||
return uri == o.uri && range == o.range;
|
return uri == o.uri && range == o.range;
|
||||||
}
|
}
|
||||||
bool operator<(const Location &o) const {
|
bool operator<(const Location &o) const {
|
||||||
return !(uri.raw_uri == o.uri.raw_uri) ? uri.raw_uri < o.uri.raw_uri
|
return !(uri == o.uri) ? uri < o.uri : range < o.range;
|
||||||
: range < o.range;
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LocationLink {
|
||||||
|
std::string targetUri;
|
||||||
|
lsRange targetRange;
|
||||||
|
lsRange targetSelectionRange;
|
||||||
|
explicit operator bool() const { return targetUri.size(); }
|
||||||
|
explicit operator Location() && {
|
||||||
|
return {DocumentUri{std::move(targetUri)}, targetSelectionRange};
|
||||||
|
}
|
||||||
|
bool operator==(const LocationLink &o) const {
|
||||||
|
return targetUri == o.targetUri &&
|
||||||
|
targetSelectionRange == o.targetSelectionRange;
|
||||||
|
}
|
||||||
|
bool operator<(const LocationLink &o) const {
|
||||||
|
return !(targetUri == o.targetUri)
|
||||||
|
? targetUri < o.targetUri
|
||||||
|
: targetSelectionRange < o.targetSelectionRange;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,6 +116,21 @@ void ReplyOnce::NotReady(bool file) {
|
|||||||
Error(ErrorCode::InternalError, "not indexed");
|
Error(ErrorCode::InternalError, "not indexed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReplyOnce::ReplyLocationLink(std::vector<LocationLink> &result) {
|
||||||
|
std::sort(result.begin(), result.end());
|
||||||
|
result.erase(std::unique(result.begin(), result.end()), result.end());
|
||||||
|
if (result.size() > g_config->xref.maxNum)
|
||||||
|
result.resize(g_config->xref.maxNum);
|
||||||
|
if (g_config->client.linkSupport) {
|
||||||
|
(*this)(result);
|
||||||
|
} else {
|
||||||
|
std::vector<Location> result1;
|
||||||
|
for (auto &loc : result)
|
||||||
|
result1.emplace_back(std::move(loc));
|
||||||
|
(*this)(result1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageHandler::Bind(const char *method,
|
void MessageHandler::Bind(const char *method,
|
||||||
void (MessageHandler::*handler)(JsonReader &)) {
|
void (MessageHandler::*handler)(JsonReader &)) {
|
||||||
method2notification[method] = [this, handler](JsonReader &reader) {
|
method2notification[method] = [this, handler](JsonReader &reader) {
|
||||||
@ -155,6 +170,7 @@ void MessageHandler::Bind(const char *method,
|
|||||||
}
|
}
|
||||||
|
|
||||||
MessageHandler::MessageHandler() {
|
MessageHandler::MessageHandler() {
|
||||||
|
// clang-format off
|
||||||
Bind("$ccls/call", &MessageHandler::ccls_call);
|
Bind("$ccls/call", &MessageHandler::ccls_call);
|
||||||
Bind("$ccls/fileInfo", &MessageHandler::ccls_fileInfo);
|
Bind("$ccls/fileInfo", &MessageHandler::ccls_fileInfo);
|
||||||
Bind("$ccls/info", &MessageHandler::ccls_info);
|
Bind("$ccls/info", &MessageHandler::ccls_info);
|
||||||
@ -169,39 +185,31 @@ MessageHandler::MessageHandler() {
|
|||||||
Bind("textDocument/codeAction", &MessageHandler::textDocument_codeAction);
|
Bind("textDocument/codeAction", &MessageHandler::textDocument_codeAction);
|
||||||
Bind("textDocument/codeLens", &MessageHandler::textDocument_codeLens);
|
Bind("textDocument/codeLens", &MessageHandler::textDocument_codeLens);
|
||||||
Bind("textDocument/completion", &MessageHandler::textDocument_completion);
|
Bind("textDocument/completion", &MessageHandler::textDocument_completion);
|
||||||
|
Bind("textDocument/declaration", &MessageHandler::textDocument_declaration);
|
||||||
Bind("textDocument/definition", &MessageHandler::textDocument_definition);
|
Bind("textDocument/definition", &MessageHandler::textDocument_definition);
|
||||||
Bind("textDocument/didChange", &MessageHandler::textDocument_didChange);
|
Bind("textDocument/didChange", &MessageHandler::textDocument_didChange);
|
||||||
Bind("textDocument/didClose", &MessageHandler::textDocument_didClose);
|
Bind("textDocument/didClose", &MessageHandler::textDocument_didClose);
|
||||||
Bind("textDocument/didOpen", &MessageHandler::textDocument_didOpen);
|
Bind("textDocument/didOpen", &MessageHandler::textDocument_didOpen);
|
||||||
Bind("textDocument/didSave", &MessageHandler::textDocument_didSave);
|
Bind("textDocument/didSave", &MessageHandler::textDocument_didSave);
|
||||||
Bind("textDocument/documentHighlight",
|
Bind("textDocument/documentHighlight", &MessageHandler::textDocument_documentHighlight);
|
||||||
&MessageHandler::textDocument_documentHighlight);
|
|
||||||
Bind("textDocument/documentLink", &MessageHandler::textDocument_documentLink);
|
Bind("textDocument/documentLink", &MessageHandler::textDocument_documentLink);
|
||||||
Bind("textDocument/documentSymbol",
|
Bind("textDocument/documentSymbol", &MessageHandler::textDocument_documentSymbol);
|
||||||
&MessageHandler::textDocument_documentSymbol);
|
|
||||||
Bind("textDocument/foldingRange", &MessageHandler::textDocument_foldingRange);
|
Bind("textDocument/foldingRange", &MessageHandler::textDocument_foldingRange);
|
||||||
Bind("textDocument/formatting", &MessageHandler::textDocument_formatting);
|
Bind("textDocument/formatting", &MessageHandler::textDocument_formatting);
|
||||||
Bind("textDocument/hover", &MessageHandler::textDocument_hover);
|
Bind("textDocument/hover", &MessageHandler::textDocument_hover);
|
||||||
Bind("textDocument/implementation",
|
Bind("textDocument/implementation", &MessageHandler::textDocument_implementation);
|
||||||
&MessageHandler::textDocument_implementation);
|
Bind("textDocument/onTypeFormatting", &MessageHandler::textDocument_onTypeFormatting);
|
||||||
Bind("textDocument/onTypeFormatting",
|
Bind("textDocument/rangeFormatting", &MessageHandler::textDocument_rangeFormatting);
|
||||||
&MessageHandler::textDocument_onTypeFormatting);
|
|
||||||
Bind("textDocument/rangeFormatting",
|
|
||||||
&MessageHandler::textDocument_rangeFormatting);
|
|
||||||
Bind("textDocument/references", &MessageHandler::textDocument_references);
|
Bind("textDocument/references", &MessageHandler::textDocument_references);
|
||||||
Bind("textDocument/rename", &MessageHandler::textDocument_rename);
|
Bind("textDocument/rename", &MessageHandler::textDocument_rename);
|
||||||
Bind("textDocument/signatureHelp",
|
Bind("textDocument/signatureHelp", &MessageHandler::textDocument_signatureHelp);
|
||||||
&MessageHandler::textDocument_signatureHelp);
|
Bind("textDocument/typeDefinition", &MessageHandler::textDocument_typeDefinition);
|
||||||
Bind("textDocument/typeDefinition",
|
Bind("workspace/didChangeConfiguration", &MessageHandler::workspace_didChangeConfiguration);
|
||||||
&MessageHandler::textDocument_typeDefinition);
|
Bind("workspace/didChangeWatchedFiles", &MessageHandler::workspace_didChangeWatchedFiles);
|
||||||
Bind("workspace/didChangeConfiguration",
|
Bind("workspace/didChangeWorkspaceFolders", &MessageHandler::workspace_didChangeWorkspaceFolders);
|
||||||
&MessageHandler::workspace_didChangeConfiguration);
|
|
||||||
Bind("workspace/didChangeWatchedFiles",
|
|
||||||
&MessageHandler::workspace_didChangeWatchedFiles);
|
|
||||||
Bind("workspace/didChangeWorkspaceFolders",
|
|
||||||
&MessageHandler::workspace_didChangeWorkspaceFolders);
|
|
||||||
Bind("workspace/executeCommand", &MessageHandler::workspace_executeCommand);
|
Bind("workspace/executeCommand", &MessageHandler::workspace_executeCommand);
|
||||||
Bind("workspace/symbol", &MessageHandler::workspace_symbol);
|
Bind("workspace/symbol", &MessageHandler::workspace_symbol);
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageHandler::Run(InMessage &msg) {
|
void MessageHandler::Run(InMessage &msg) {
|
||||||
|
@ -189,6 +189,7 @@ REFLECT_STRUCT(ResponseError, code, message);
|
|||||||
REFLECT_STRUCT(Position, line, character);
|
REFLECT_STRUCT(Position, line, character);
|
||||||
REFLECT_STRUCT(lsRange, start, end);
|
REFLECT_STRUCT(lsRange, start, end);
|
||||||
REFLECT_STRUCT(Location, uri, range);
|
REFLECT_STRUCT(Location, uri, range);
|
||||||
|
REFLECT_STRUCT(LocationLink, targetUri, targetRange, targetSelectionRange);
|
||||||
REFLECT_UNDERLYING_B(SymbolKind);
|
REFLECT_UNDERLYING_B(SymbolKind);
|
||||||
REFLECT_STRUCT(TextDocumentIdentifier, uri);
|
REFLECT_STRUCT(TextDocumentIdentifier, uri);
|
||||||
REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text);
|
REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text);
|
||||||
@ -210,6 +211,7 @@ struct ReplyOnce {
|
|||||||
pipeline::ReplyError(id, [&](JsonWriter &w) { Reflect(w, err); });
|
pipeline::ReplyError(id, [&](JsonWriter &w) { Reflect(w, err); });
|
||||||
}
|
}
|
||||||
void NotReady(bool file);
|
void NotReady(bool file);
|
||||||
|
void ReplyLocationLink(std::vector<LocationLink> &result);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MessageHandler {
|
struct MessageHandler {
|
||||||
@ -252,6 +254,7 @@ private:
|
|||||||
void textDocument_codeAction(CodeActionParam &, ReplyOnce &);
|
void textDocument_codeAction(CodeActionParam &, ReplyOnce &);
|
||||||
void textDocument_codeLens(TextDocumentParam &, ReplyOnce &);
|
void textDocument_codeLens(TextDocumentParam &, ReplyOnce &);
|
||||||
void textDocument_completion(CompletionParam &, ReplyOnce &);
|
void textDocument_completion(CompletionParam &, ReplyOnce &);
|
||||||
|
void textDocument_declaration(TextDocumentPositionParam &, ReplyOnce &);
|
||||||
void textDocument_definition(TextDocumentPositionParam &, ReplyOnce &);
|
void textDocument_definition(TextDocumentPositionParam &, ReplyOnce &);
|
||||||
void textDocument_didChange(TextDocumentDidChangeParam &);
|
void textDocument_didChange(TextDocumentDidChangeParam &);
|
||||||
void textDocument_didClose(TextDocumentParam &);
|
void textDocument_didClose(TextDocumentParam &);
|
||||||
|
@ -51,12 +51,14 @@ void MessageHandler::ccls_vars(JsonReader &reader, ReplyOnce &reply) {
|
|||||||
usr = def->type;
|
usr = def->type;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case Kind::Type:
|
case Kind::Type: {
|
||||||
result = GetLsLocations(
|
for (DeclRef dr :
|
||||||
db, wfiles,
|
GetVarDeclarations(db, db->Type(usr).instances, param.kind))
|
||||||
GetVarDeclarations(db, db->Type(usr).instances, param.kind));
|
if (auto loc = GetLocationLink(db, wfiles, dr))
|
||||||
|
result.push_back(Location(std::move(loc)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
reply(result);
|
reply(result);
|
||||||
}
|
}
|
||||||
|
@ -173,6 +173,11 @@ struct TextDocumentClientCap {
|
|||||||
} completionItem;
|
} completionItem;
|
||||||
} completion;
|
} completion;
|
||||||
|
|
||||||
|
// Ignore declaration, implementation, typeDefinition
|
||||||
|
struct LinkSupport {
|
||||||
|
bool linkSupport = false;
|
||||||
|
} definition;
|
||||||
|
|
||||||
struct DocumentSymbol {
|
struct DocumentSymbol {
|
||||||
bool hierarchicalDocumentSymbolSupport = false;
|
bool hierarchicalDocumentSymbolSupport = false;
|
||||||
} documentSymbol;
|
} documentSymbol;
|
||||||
@ -183,7 +188,8 @@ REFLECT_STRUCT(TextDocumentClientCap::Completion::CompletionItem,
|
|||||||
REFLECT_STRUCT(TextDocumentClientCap::Completion, completionItem);
|
REFLECT_STRUCT(TextDocumentClientCap::Completion, completionItem);
|
||||||
REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol,
|
REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol,
|
||||||
hierarchicalDocumentSymbolSupport);
|
hierarchicalDocumentSymbolSupport);
|
||||||
REFLECT_STRUCT(TextDocumentClientCap, completion, documentSymbol);
|
REFLECT_STRUCT(TextDocumentClientCap::LinkSupport, linkSupport);
|
||||||
|
REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol);
|
||||||
|
|
||||||
struct ClientCap {
|
struct ClientCap {
|
||||||
WorkspaceClientCap workspace;
|
WorkspaceClientCap workspace;
|
||||||
@ -284,11 +290,13 @@ void Initialize(MessageHandler *m, InitializeParam ¶m, ReplyOnce &reply) {
|
|||||||
|
|
||||||
// Client capabilities
|
// Client capabilities
|
||||||
const auto &capabilities = param.capabilities;
|
const auto &capabilities = param.capabilities;
|
||||||
g_config->client.snippetSupport &=
|
|
||||||
capabilities.textDocument.completion.completionItem.snippetSupport;
|
|
||||||
g_config->client.hierarchicalDocumentSymbolSupport &=
|
g_config->client.hierarchicalDocumentSymbolSupport &=
|
||||||
capabilities.textDocument.documentSymbol
|
capabilities.textDocument.documentSymbol
|
||||||
.hierarchicalDocumentSymbolSupport;
|
.hierarchicalDocumentSymbolSupport;
|
||||||
|
g_config->client.linkSupport &=
|
||||||
|
capabilities.textDocument.definition.linkSupport;
|
||||||
|
g_config->client.snippetSupport &=
|
||||||
|
capabilities.textDocument.completion.completionItem.snippetSupport;
|
||||||
|
|
||||||
// Ensure there is a resource directory.
|
// Ensure there is a resource directory.
|
||||||
if (g_config->clang.resourceDir.empty())
|
if (g_config->clang.resourceDir.empty())
|
||||||
|
@ -45,6 +45,27 @@ std::vector<DeclRef> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void MessageHandler::textDocument_declaration(TextDocumentPositionParam ¶m,
|
||||||
|
ReplyOnce &reply) {
|
||||||
|
int file_id;
|
||||||
|
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
|
||||||
|
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
||||||
|
if (!wf) {
|
||||||
|
reply.NotReady(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<LocationLink> result;
|
||||||
|
Position &ls_pos = param.position;
|
||||||
|
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position))
|
||||||
|
for (DeclRef dr : GetNonDefDeclarations(db, sym))
|
||||||
|
if (!(dr.file_id == file_id &&
|
||||||
|
dr.range.Contains(ls_pos.line, ls_pos.character)))
|
||||||
|
if (auto loc = GetLocationLink(db, wfiles, dr))
|
||||||
|
result.push_back(loc);
|
||||||
|
reply.ReplyLocationLink(result);
|
||||||
|
}
|
||||||
|
|
||||||
void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
|
void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
int file_id;
|
int file_id;
|
||||||
@ -55,54 +76,52 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Location> result;
|
std::vector<LocationLink> result;
|
||||||
Maybe<Use> on_def;
|
Maybe<DeclRef> on_def;
|
||||||
Position &ls_pos = param.position;
|
Position &ls_pos = param.position;
|
||||||
|
|
||||||
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, ls_pos, true)) {
|
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, ls_pos, true)) {
|
||||||
// Special cases which are handled:
|
// Special cases which are handled:
|
||||||
// - symbol has declaration but no definition (ie, pure virtual)
|
// - symbol has declaration but no definition (ie, pure virtual)
|
||||||
// - goto declaration while in definition of recursive type
|
// - goto declaration while in definition of recursive type
|
||||||
std::vector<Use> uses;
|
std::vector<DeclRef> drs;
|
||||||
EachEntityDef(db, sym, [&](const auto &def) {
|
EachEntityDef(db, sym, [&](const auto &def) {
|
||||||
if (def.spell) {
|
if (def.spell) {
|
||||||
Use spell = *def.spell;
|
DeclRef spell = *def.spell;
|
||||||
if (spell.file_id == file_id &&
|
if (spell.file_id == file_id &&
|
||||||
spell.range.Contains(ls_pos.line, ls_pos.character)) {
|
spell.range.Contains(ls_pos.line, ls_pos.character)) {
|
||||||
on_def = spell;
|
on_def = spell;
|
||||||
uses.clear();
|
drs.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uses.push_back(spell);
|
drs.push_back(spell);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// |uses| is empty if on a declaration/definition, otherwise it includes
|
// |uses| is empty if on a declaration/definition, otherwise it includes
|
||||||
// all declarations/definitions.
|
// all declarations/definitions.
|
||||||
if (uses.empty()) {
|
if (drs.empty()) {
|
||||||
for (Use use : GetNonDefDeclarationTargets(db, sym))
|
for (DeclRef dr : GetNonDefDeclarationTargets(db, sym))
|
||||||
if (!(use.file_id == file_id &&
|
if (!(dr.file_id == file_id &&
|
||||||
use.range.Contains(ls_pos.line, ls_pos.character)))
|
dr.range.Contains(ls_pos.line, ls_pos.character)))
|
||||||
uses.push_back(use);
|
drs.push_back(dr);
|
||||||
// There is no declaration but the cursor is on a definition.
|
// There is no declaration but the cursor is on a definition.
|
||||||
if (uses.empty() && on_def)
|
if (drs.empty() && on_def)
|
||||||
uses.push_back(*on_def);
|
drs.push_back(*on_def);
|
||||||
}
|
}
|
||||||
auto locs = GetLsLocations(db, wfiles, uses);
|
for (DeclRef dr : drs)
|
||||||
result.insert(result.end(), locs.begin(), locs.end());
|
if (auto loc = GetLocationLink(db, wfiles, dr))
|
||||||
|
result.push_back(loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.size()) {
|
if (result.empty()) {
|
||||||
std::sort(result.begin(), result.end());
|
|
||||||
result.erase(std::unique(result.begin(), result.end()), result.end());
|
|
||||||
} else {
|
|
||||||
Maybe<Range> range;
|
Maybe<Range> range;
|
||||||
// Check #include
|
// Check #include
|
||||||
for (const IndexInclude &include : file->def->includes) {
|
for (const IndexInclude &include : file->def->includes) {
|
||||||
if (include.line == ls_pos.line) {
|
if (include.line == ls_pos.line) {
|
||||||
result.push_back(
|
result.push_back(
|
||||||
Location{DocumentUri::FromPath(include.resolved_path)});
|
{DocumentUri::FromPath(include.resolved_path).raw_uri});
|
||||||
range = {{0, 0}, {0, 0}};
|
range = {{0, 0}, {0, 0}};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -160,13 +179,13 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
|
|||||||
if (best_sym.kind != Kind::Invalid) {
|
if (best_sym.kind != Kind::Invalid) {
|
||||||
Maybe<DeclRef> dr = GetDefinitionSpell(db, best_sym);
|
Maybe<DeclRef> dr = GetDefinitionSpell(db, best_sym);
|
||||||
assert(dr);
|
assert(dr);
|
||||||
if (auto loc = GetLsLocation(db, wfiles, *dr))
|
if (auto loc = GetLocationLink(db, wfiles, *dr))
|
||||||
result.push_back(*loc);
|
result.push_back(loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reply(result);
|
reply.ReplyLocationLink(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageHandler::textDocument_typeDefinition(
|
void MessageHandler::textDocument_typeDefinition(
|
||||||
@ -178,17 +197,16 @@ void MessageHandler::textDocument_typeDefinition(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Location> result;
|
std::vector<LocationLink> result;
|
||||||
auto Add = [&](const QueryType &type) {
|
auto Add = [&](const QueryType &type) {
|
||||||
for (const auto &def : type.def)
|
for (const auto &def : type.def)
|
||||||
if (def.spell) {
|
if (def.spell)
|
||||||
if (auto ls_loc = GetLsLocation(db, wfiles, *def.spell))
|
if (auto loc = GetLocationLink(db, wfiles, *def.spell))
|
||||||
result.push_back(*ls_loc);
|
result.push_back(loc);
|
||||||
}
|
|
||||||
if (result.empty())
|
if (result.empty())
|
||||||
for (const DeclRef &dr : type.declarations)
|
for (const DeclRef &dr : type.declarations)
|
||||||
if (auto ls_loc = GetLsLocation(db, wfiles, dr))
|
if (auto loc = GetLocationLink(db, wfiles, dr))
|
||||||
result.push_back(*ls_loc);
|
result.push_back(loc);
|
||||||
};
|
};
|
||||||
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
|
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
|
||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
@ -211,8 +229,6 @@ void MessageHandler::textDocument_typeDefinition(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(result.begin(), result.end());
|
reply.ReplyLocationLink(result);
|
||||||
result.erase(std::unique(result.begin(), result.end()), result.end());
|
|
||||||
reply(result);
|
|
||||||
}
|
}
|
||||||
} // namespace ccls
|
} // namespace ccls
|
||||||
|
29
src/query.cc
29
src/query.cc
@ -532,9 +532,9 @@ std::vector<Use> GetFuncDeclarations(DB *db, const std::vector<Usr> &usrs) {
|
|||||||
std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
|
std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
|
||||||
return GetDeclarations(db->type_usr, db->types, usrs);
|
return GetDeclarations(db->type_usr, db->types, usrs);
|
||||||
}
|
}
|
||||||
std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
|
std::vector<DeclRef> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
|
||||||
unsigned kind) {
|
unsigned kind) {
|
||||||
std::vector<Use> ret;
|
std::vector<DeclRef> ret;
|
||||||
ret.reserve(usrs.size());
|
ret.reserve(usrs.size());
|
||||||
for (Usr usr : usrs) {
|
for (Usr usr : usrs) {
|
||||||
QueryVar &var = db->Var(usr);
|
QueryVar &var = db->Var(usr);
|
||||||
@ -681,17 +681,18 @@ std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
|
|||||||
return GetLsLocation(db, wfiles, Use{{sym.range, sym.role}, file_id});
|
return GetLsLocation(db, wfiles, Use{{sym.range, sym.role}, file_id});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Location> GetLsLocations(DB *db, WorkingFiles *wfiles,
|
LocationLink GetLocationLink(DB *db, WorkingFiles *wfiles, DeclRef dr) {
|
||||||
const std::vector<Use> &uses) {
|
std::string path;
|
||||||
std::vector<Location> ret;
|
DocumentUri uri = GetLsDocumentUri(db, dr.file_id, &path);
|
||||||
for (Use use : uses)
|
if (auto range = GetLsRange(wfiles->GetFile(path), dr.range))
|
||||||
if (auto loc = GetLsLocation(db, wfiles, use))
|
if (auto extent = GetLsRange(wfiles->GetFile(path), dr.extent)) {
|
||||||
ret.push_back(*loc);
|
LocationLink ret;
|
||||||
std::sort(ret.begin(), ret.end());
|
ret.targetUri = uri.raw_uri;
|
||||||
ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
|
ret.targetSelectionRange = *range;
|
||||||
if (ret.size() > g_config->xref.maxNum)
|
ret.targetRange = extent->Includes(*range) ? *extent : *range;
|
||||||
ret.resize(g_config->xref.maxNum);
|
return ret;
|
||||||
return ret;
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
|
SymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
|
||||||
|
@ -200,7 +200,7 @@ Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym);
|
|||||||
// for each id.
|
// for each id.
|
||||||
std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &);
|
std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &);
|
||||||
std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
|
std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
|
||||||
std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
|
std::vector<DeclRef> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
|
||||||
|
|
||||||
// Get non-defining declarations.
|
// Get non-defining declarations.
|
||||||
std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym);
|
std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym);
|
||||||
@ -215,8 +215,8 @@ DocumentUri GetLsDocumentUri(DB *db, int file_id);
|
|||||||
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use);
|
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use);
|
||||||
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
|
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
|
||||||
SymbolRef sym, int file_id);
|
SymbolRef sym, int file_id);
|
||||||
std::vector<Location> GetLsLocations(DB *db, WorkingFiles *wfiles,
|
LocationLink GetLocationLink(DB *db, WorkingFiles *wfiles, DeclRef dr);
|
||||||
const std::vector<Use> &uses);
|
|
||||||
// Returns a symbol. The symbol will *NOT* have a location assigned.
|
// Returns a symbol. The symbol will *NOT* have a location assigned.
|
||||||
std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
|
std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
|
||||||
bool detailed);
|
bool detailed);
|
||||||
|
Loading…
Reference in New Issue
Block a user