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; lsPosition position = request->params.position;
const std::string& buffer = working_file->buffer_content; const std::string& buffer = working_file->buffer_content;
std::string_view query = LexIdentifierAroundPos(position, buffer); 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 // 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. // 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}; std::tuple<int, int, bool, int> best_score{INT_MAX, 0, true, 0};
int best_i = -1; int best_i = -1;
@ -139,21 +144,28 @@ struct Handler_TextDocumentDefinition
if (db->symbols[i].kind == SymbolKind::Invalid) if (db->symbols[i].kind == SymbolKind::Invalid)
continue; continue;
std::string_view name = has_scope ? db->GetSymbolDetailedName(i) std::string_view name = short_query.size() < query.size()
: db->GetSymbolShortName(i); ? db->GetSymbolDetailedName(i)
auto pos = name.find(query); : db->GetSymbolShortName(i);
auto pos = name.rfind(short_query);
if (pos == std::string::npos) if (pos == std::string::npos)
continue; continue;
Maybe<Use> use = GetDefinitionSpell(db, db->symbols[i]); if (Maybe<Use> use = GetDefinitionSpell(db, db->symbols[i])) {
if (!use) std::tuple<int, int, bool, int> score{
continue; int(name.size() - short_query.size()), -pos,
use->file != file_id,
std::tuple<int, int, bool, int> score{ std::abs(use->range.start.line - position.line)};
int(name.size() - query.size()), int(pos), use->file != file_id, // Update the score with qualified name if the qualified name
std::abs(use->range.start.line - position.line)}; // occurs in |name|.
if (score < best_score) { pos = name.rfind(query);
best_score = score; if (pos != std::string::npos) {
best_i = i; 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) { 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 // 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()) if (ending.size() > value.size())
return false; return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); 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()) if (start.size() > value.size())
return false; return false;
return std::equal(start.begin(), start.end(), value.begin()); return std::equal(start.begin(), start.end(), value.begin());

View File

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