mirror of
https://github.com/MaskRay/ccls.git
synced 2025-01-19 12:05:50 +00:00
Goto definition intelligently jumps to declaration
This commit is contained in:
parent
76b6a3d4fd
commit
c9a251b7ab
@ -36,6 +36,18 @@ const int kNumIndexers = 8 - 1;
|
|||||||
const int kQueueSizeBytes = 1024 * 8;
|
const int kQueueSizeBytes = 1024 * 8;
|
||||||
const int kMaxWorkspaceSearchResults = 1000;
|
const int kMaxWorkspaceSearchResults = 1000;
|
||||||
|
|
||||||
|
QueryableFile* FindFile(QueryableDatabase* db, const std::string& filename, QueryFileId* file_id) {
|
||||||
|
auto it = db->usr_to_symbol.find(filename);
|
||||||
|
if (it != db->usr_to_symbol.end()) {
|
||||||
|
*file_id = QueryFileId(it->second.idx);
|
||||||
|
return &db->files[it->second.idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Unable to find file " << filename << std::endl;
|
||||||
|
*file_id = QueryFileId(-1);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
QueryableFile* FindFile(QueryableDatabase* db, const std::string& filename) {
|
QueryableFile* FindFile(QueryableDatabase* db, const std::string& filename) {
|
||||||
auto it = db->usr_to_symbol.find(filename);
|
auto it = db->usr_to_symbol.find(filename);
|
||||||
if (it != db->usr_to_symbol.end())
|
if (it != db->usr_to_symbol.end())
|
||||||
@ -149,6 +161,21 @@ optional<QueryableLocation> GetDefinitionExtentOfSymbol(QueryableDatabase* db, c
|
|||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<QueryableLocation> GetDeclarationsOfSymbol(QueryableDatabase* db, const SymbolIdx& symbol) {
|
||||||
|
switch (symbol.kind) {
|
||||||
|
case SymbolKind::Func:
|
||||||
|
return db->funcs[symbol.idx].declarations;
|
||||||
|
case SymbolKind::Var: {
|
||||||
|
optional<QueryableLocation> declaration = db->vars[symbol.idx].def.declaration;
|
||||||
|
if (declaration)
|
||||||
|
return { *declaration };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
|
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
|
||||||
if (!working_file) {
|
if (!working_file) {
|
||||||
return lsRange(
|
return lsRange(
|
||||||
@ -738,7 +765,8 @@ void QueryDbMainLoop(
|
|||||||
case IpcId::TextDocumentDefinition: {
|
case IpcId::TextDocumentDefinition: {
|
||||||
auto msg = static_cast<Ipc_TextDocumentDefinition*>(message.get());
|
auto msg = static_cast<Ipc_TextDocumentDefinition*>(message.get());
|
||||||
|
|
||||||
QueryableFile* file = FindFile(db, msg->params.textDocument.uri.GetPath());
|
QueryFileId file_id;
|
||||||
|
QueryableFile* file = FindFile(db, msg->params.textDocument.uri.GetPath(), &file_id);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl;
|
std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl;
|
||||||
break;
|
break;
|
||||||
@ -751,19 +779,37 @@ void QueryDbMainLoop(
|
|||||||
int target_column = msg->params.position.character + 1;
|
int target_column = msg->params.position.character + 1;
|
||||||
|
|
||||||
for (const SymbolRef& ref : file->def.all_symbols) {
|
for (const SymbolRef& ref : file->def.all_symbols) {
|
||||||
if (ref.loc.range.start.line >= target_line && ref.loc.range.end.line <= target_line &&
|
if (ref.loc.range.Contains(target_line, target_column)) {
|
||||||
ref.loc.range.start.column <= target_column && ref.loc.range.end.column >= target_column) {
|
|
||||||
// Found symbol. Return definition.
|
// Found symbol. Return definition.
|
||||||
optional<QueryableLocation> spelling = GetDefinitionSpellingOfSymbol(db, ref.idx);
|
optional<QueryableLocation> definition_spelling = GetDefinitionSpellingOfSymbol(db, ref.idx);
|
||||||
if (spelling) {
|
if (definition_spelling) {
|
||||||
|
|
||||||
|
// If the cursor is currently at the definition we should goto the declaration if possible.
|
||||||
|
if (definition_spelling->path == file_id && definition_spelling->range.Contains(target_line, target_column)) {
|
||||||
|
// Goto declaration.
|
||||||
|
|
||||||
|
std::vector<QueryableLocation> declarations = GetDeclarationsOfSymbol(db, ref.idx);
|
||||||
|
for (auto declaration : declarations) {
|
||||||
|
optional<lsLocation> ls_declaration = GetLsLocation(db, working_files, declaration);
|
||||||
|
if (ls_declaration)
|
||||||
|
response.result.push_back(*ls_declaration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.result.empty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Goto definition.
|
||||||
|
|
||||||
// We use spelling start and extent end because this causes vscode
|
// We use spelling start and extent end because this causes vscode
|
||||||
// to highlight the entire definition when previewing / hoving with
|
// to highlight the entire definition when previewing / hoving with
|
||||||
// the mouse.
|
// the mouse.
|
||||||
optional<QueryableLocation> extent = GetDefinitionExtentOfSymbol(db, ref.idx);
|
optional<QueryableLocation> extent = GetDefinitionExtentOfSymbol(db, ref.idx);
|
||||||
if (extent)
|
if (extent)
|
||||||
spelling->range.end = extent->range.end;
|
definition_spelling->range.end = extent->range.end;
|
||||||
|
|
||||||
optional<lsLocation> ls_location = GetLsLocation(db, working_files, spelling.value());
|
optional<lsLocation> ls_location = GetLsLocation(db, working_files, definition_spelling.value());
|
||||||
if (ls_location)
|
if (ls_location)
|
||||||
response.result.push_back(*ls_location);
|
response.result.push_back(*ls_location);
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,18 @@ Range::Range(const char* encoded) {
|
|||||||
end.column = atoi(encoded);
|
end.column = atoi(encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Range::Contains(int line, int column) const {
|
||||||
|
if (line == start.line && line == end.line)
|
||||||
|
return column >= start.column && column <= end.column;
|
||||||
|
if (line == start.line)
|
||||||
|
return column >= start.column;
|
||||||
|
if (line == end.line)
|
||||||
|
return column <= end.column;
|
||||||
|
if (line > start.line && line < end.line)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Range::ToString() {
|
std::string Range::ToString() {
|
||||||
// Output looks like this:
|
// Output looks like this:
|
||||||
//
|
//
|
||||||
|
@ -31,6 +31,8 @@ struct Range {
|
|||||||
Range(bool interesting, Position start, Position end);
|
Range(bool interesting, Position start, Position end);
|
||||||
explicit Range(const char* encoded);
|
explicit Range(const char* encoded);
|
||||||
|
|
||||||
|
bool Contains(int line, int column) const;
|
||||||
|
|
||||||
std::string ToString();
|
std::string ToString();
|
||||||
Range WithInteresting(bool interesting);
|
Range WithInteresting(bool interesting);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user