Better textDocument/definition heuristic for T::name style dependent names

This commit is contained in:
Fangrui Song 2018-03-29 16:57:10 -07:00
parent 53138afabd
commit 39dfe052f5
3 changed files with 32 additions and 19 deletions

View File

@ -128,10 +128,15 @@ struct Handler_TextDocumentDefinition
lsPosition position = request->params.position;
const std::string& buffer = working_file->buffer_content;
std::string_view query = LexIdentifierAroundPos(position, buffer);
bool has_scope = query.find(':') != std::string::npos;
std::string_view short_query = query;
{
auto pos = query.rfind(':');
if (pos != std::string::npos)
short_query = query.substr(pos + 1);
}
// For symbols whose short/detailed names contain |query| as a
// substring, we use the tuple <length difference, matching position,
// substring, we use the tuple <length difference, negative position,
// not in the same file, line distance> to find the best match.
std::tuple<int, int, bool, int> best_score{INT_MAX, 0, true, 0};
int best_i = -1;
@ -139,21 +144,28 @@ struct Handler_TextDocumentDefinition
if (db->symbols[i].kind == SymbolKind::Invalid)
continue;
std::string_view name = has_scope ? db->GetSymbolDetailedName(i)
: db->GetSymbolShortName(i);
auto pos = name.find(query);
std::string_view name = short_query.size() < query.size()
? db->GetSymbolDetailedName(i)
: db->GetSymbolShortName(i);
auto pos = name.rfind(short_query);
if (pos == std::string::npos)
continue;
Maybe<Use> use = GetDefinitionSpell(db, db->symbols[i]);
if (!use)
continue;
std::tuple<int, int, bool, int> score{
int(name.size() - query.size()), int(pos), use->file != file_id,
std::abs(use->range.start.line - position.line)};
if (score < best_score) {
best_score = score;
best_i = i;
if (Maybe<Use> use = GetDefinitionSpell(db, db->symbols[i])) {
std::tuple<int, int, bool, int> score{
int(name.size() - short_query.size()), -pos,
use->file != file_id,
std::abs(use->range.start.line - position.line)};
// Update the score with qualified name if the qualified name
// occurs in |name|.
pos = name.rfind(query);
if (pos != std::string::npos) {
std::get<0>(score) = int(name.size() - query.size());
std::get<1>(score) = -pos;
}
if (score < best_score) {
best_score = score;
best_i = i;
}
}
}
if (best_i != -1) {

View File

@ -77,13 +77,13 @@ uint64_t HashUsr(const char* s, size_t n) {
}
// See http://stackoverflow.com/a/2072890
bool EndsWith(const std::string& value, const std::string& ending) {
bool EndsWith(std::string_view value, std::string_view ending) {
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
bool StartsWith(const std::string& value, const std::string& start) {
bool StartsWith(std::string_view value, std::string_view start) {
if (start.size() > value.size())
return false;
return std::equal(start.begin(), start.end(), value.begin());

View File

@ -1,6 +1,7 @@
#pragma once
#include <optional.h>
#include <string_view.h>
#include <algorithm>
#include <functional>
@ -22,8 +23,8 @@ uint64_t HashUsr(const char* s);
uint64_t HashUsr(const char* s, size_t n);
// Returns true if |value| starts/ends with |start| or |ending|.
bool StartsWith(const std::string& value, const std::string& start);
bool EndsWith(const std::string& value, const std::string& ending);
bool StartsWith(std::string_view value, std::string_view start);
bool EndsWith(std::string_view value, std::string_view ending);
bool AnyStartsWith(const std::vector<std::string>& values,
const std::string& start);
bool StartsWithAny(const std::string& value,