Goto definition intelligently jumps to declaration

This commit is contained in:
Jacob Dufault 2017-04-10 22:43:01 -07:00
parent 76b6a3d4fd
commit c9a251b7ab
3 changed files with 80 additions and 20 deletions

View File

@ -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);
} }

View File

@ -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:
// //

View File

@ -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);