Simplify semantic highlighting

This commit is contained in:
Fangrui Song 2018-09-20 17:20:09 -07:00
parent d9f0de4719
commit 28401961ae
9 changed files with 47 additions and 118 deletions

View File

@ -134,7 +134,7 @@ struct Config {
// auto-completion. An example value is { ".h", ".hpp" }
//
// This is significantly faster than using a regex.
std::vector<std::string> includeSuffixWhitelist = {".h", ".hpp", ".hh"};
std::vector<std::string> includeSuffixWhitelist = {".h", ".hpp", ".hh", ".inc"};
std::vector<std::string> includeWhitelist;
} completion;

View File

@ -4,6 +4,7 @@
#include "message_handler.h"
#include "log.hh"
#include "match.h"
#include "pipeline.hh"
#include "project.h"
#include "query_utils.h"
@ -47,74 +48,34 @@ struct ScanLineEvent {
};
} // namespace
SemanticHighlightSymbolCache::Entry::Entry(
SemanticHighlightSymbolCache *all_caches, const std::string &path)
: all_caches_(all_caches), path(path) {}
std::optional<int> SemanticHighlightSymbolCache::Entry::TryGetStableId(
SymbolKind kind, const std::string &detailed_name) {
TNameToId *map = GetMapForSymbol_(kind);
auto it = map->find(detailed_name);
if (it != map->end())
return it->second;
return std::nullopt;
}
int SemanticHighlightSymbolCache::Entry::GetStableId(
SymbolKind kind, const std::string &detailed_name) {
std::optional<int> id = TryGetStableId(kind, detailed_name);
if (id)
return *id;
// Create a new id. First try to find a key in another map.
all_caches_->cache_.IterateValues([&](const std::shared_ptr<Entry> &entry) {
std::optional<int> other_id = entry->TryGetStableId(kind, detailed_name);
if (other_id) {
id = other_id;
return false;
}
return true;
});
// Create a new id.
TNameToId *map = GetMapForSymbol_(kind);
if (!id)
id = all_caches_->next_stable_id_++;
return (*map)[detailed_name] = *id;
}
SemanticHighlightSymbolCache::Entry::TNameToId *
SemanticHighlightSymbolCache::Entry::GetMapForSymbol_(SymbolKind kind) {
int SemanticHighlight::GetStableId(SymbolKind kind, Usr usr) {
decltype(func2id) *map;
switch (kind) {
case SymbolKind::Type:
return &detailed_type_name_to_stable_id;
case SymbolKind::Func:
return &detailed_func_name_to_stable_id;
map = &func2id;
break;
case SymbolKind::Type:
map = &type2id;
break;
case SymbolKind::Var:
return &detailed_var_name_to_stable_id;
map = &var2id;
break;
case SymbolKind::File:
case SymbolKind::Invalid:
break;
}
assert(false);
return nullptr;
llvm_unreachable("");
}
SemanticHighlightSymbolCache::SemanticHighlightSymbolCache()
: cache_(kCacheSize) {}
auto it = map->try_emplace(usr, next_id);
if (it.second)
next_id++;
return it.first->second;
}
void SemanticHighlightSymbolCache::Init() {
void SemanticHighlight::Init() {
match_ = std::make_unique<GroupMatch>(g_config->highlight.whitelist,
g_config->highlight.blacklist);
}
std::shared_ptr<SemanticHighlightSymbolCache::Entry>
SemanticHighlightSymbolCache::GetCacheForFile(const std::string &path) {
return cache_.Get(
path, [&, this]() { return std::make_shared<Entry>(this, path); });
}
MessageHandler::MessageHandler() {
// Dynamically allocate |message_handlers|, otherwise there will be static
// initialization order races.
@ -184,15 +145,12 @@ void EmitSkippedRanges(WorkingFile *working_file,
pipeline::WriteStdout(kMethodType_CclsPublishSkippedRanges, out);
}
void EmitSemanticHighlighting(DB *db,
SemanticHighlightSymbolCache *semantic_cache,
void EmitSemanticHighlighting(DB *db, SemanticHighlight *highlight,
WorkingFile *wfile, QueryFile *file) {
assert(file->def);
if (wfile->buffer_content.size() > g_config->largeFileSize ||
!semantic_cache->match_->IsMatch(file->def->path))
!highlight->match_->IsMatch(file->def->path))
return;
auto semantic_cache_for_file =
semantic_cache->GetCacheForFile(file->def->path);
// Group symbols together.
std::unordered_map<SymbolIdx, Out_CclsPublishSemanticHighlighting::Symbol>
@ -288,8 +246,7 @@ void EmitSemanticHighlighting(DB *db,
it->second.lsRanges.push_back(*loc);
} else {
Out_CclsPublishSemanticHighlighting::Symbol symbol;
symbol.stableId = semantic_cache_for_file->GetStableId(
sym.kind, std::string(detailed_name));
symbol.stableId = highlight->GetStableId(sym.kind, sym.usr);
symbol.parentKind = parent_kind;
symbol.kind = kind;
symbol.storage = storage;

View File

@ -5,7 +5,6 @@
#include "lru_cache.h"
#include "lsp.h"
#include "match.h"
#include "method.h"
#include "query.h"
@ -17,6 +16,7 @@
struct CompletionManager;
struct Config;
class DiagnosticsPublisher;
struct GroupMatch;
struct VFS;
struct IncludeComplete;
struct MultiQueueWaiter;
@ -27,35 +27,13 @@ struct WorkingFiles;
// Caches symbols for a single file for semantic highlighting to provide
// relatively stable ids. Only supports xxx files at a time.
struct SemanticHighlightSymbolCache {
struct Entry {
SemanticHighlightSymbolCache *all_caches_ = nullptr;
// The path this cache belongs to.
std::string path;
// Detailed symbol name to stable id.
using TNameToId = std::unordered_map<std::string, int>;
TNameToId detailed_type_name_to_stable_id;
TNameToId detailed_func_name_to_stable_id;
TNameToId detailed_var_name_to_stable_id;
Entry(SemanticHighlightSymbolCache *all_caches, const std::string &path);
std::optional<int> TryGetStableId(SymbolKind kind,
const std::string &detailed_name);
int GetStableId(SymbolKind kind, const std::string &detailed_name);
TNameToId *GetMapForSymbol_(SymbolKind kind);
};
constexpr static int kCacheSize = 10;
LruCache<std::string, Entry> cache_;
uint32_t next_stable_id_ = 0;
struct SemanticHighlight {
llvm::DenseMap<Usr, int, DenseMapInfoForUsr> func2id, type2id, var2id;
uint32_t next_id = 0;
std::unique_ptr<GroupMatch> match_;
SemanticHighlightSymbolCache();
void Init();
std::shared_ptr<Entry> GetCacheForFile(const std::string &path);
int GetStableId(SymbolKind kind, Usr usr);
};
struct Out_CclsPublishSemanticHighlighting
@ -102,7 +80,7 @@ struct MessageHandler {
Project *project = nullptr;
DiagnosticsPublisher *diag_pub = nullptr;
VFS *vfs = nullptr;
SemanticHighlightSymbolCache *semantic_cache = nullptr;
SemanticHighlight *highlight = nullptr;
WorkingFiles *working_files = nullptr;
CompletionManager *clang_complete = nullptr;
IncludeComplete *include_complete = nullptr;
@ -132,6 +110,5 @@ bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id,
void EmitSkippedRanges(WorkingFile *working_file,
const std::vector<Range> &skipped_ranges);
void EmitSemanticHighlighting(DB *db,
SemanticHighlightSymbolCache *semantic_cache,
void EmitSemanticHighlighting(DB *db, SemanticHighlight *highlight,
WorkingFile *working_file, QueryFile *file);

View File

@ -476,7 +476,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
diag_pub->Init();
idx::Init();
semantic_cache->Init();
highlight->Init();
// Open up / load the project.
project->Load(project_path);

View File

@ -48,7 +48,7 @@ struct Handler_TextDocumentDidOpen
FindFileOrFail(db, project, std::nullopt, path, &file);
if (file && file->def) {
EmitSkippedRanges(working_file, file->def->skipped_ranges);
EmitSemanticHighlighting(db, semantic_cache, working_file, file);
EmitSemanticHighlighting(db, highlight, working_file, file);
}
include_complete->AddFile(working_file->filename);

View File

@ -8,6 +8,7 @@
#include "include_complete.h"
#include "log.hh"
#include "lsp.h"
#include "match.h"
#include "message_handler.h"
#include "pipeline.hh"
#include "platform.h"
@ -358,7 +359,7 @@ void Indexer_Main(CompletionManager *completion, VFS *vfs, Project *project,
indexer_waiter->Wait(index_request);
}
void Main_OnIndexed(DB *db, SemanticHighlightSymbolCache *semantic_cache,
void Main_OnIndexed(DB *db, SemanticHighlight *highlight,
WorkingFiles *working_files, IndexUpdate *update) {
if (update->refresh) {
LOG_S(INFO)
@ -369,7 +370,7 @@ void Main_OnIndexed(DB *db, SemanticHighlightSymbolCache *semantic_cache,
if (db->name2file_id.find(filename) == db->name2file_id.end())
continue;
QueryFile *file = &db->files[db->name2file_id[filename]];
EmitSemanticHighlighting(db, semantic_cache, f.get(), file);
EmitSemanticHighlighting(db, highlight, f.get(), file);
}
return;
}
@ -389,7 +390,7 @@ void Main_OnIndexed(DB *db, SemanticHighlightSymbolCache *semantic_cache,
wfile->SetIndexContent(g_config->index.onChange ? wfile->buffer_content
: def_u.second);
EmitSkippedRanges(wfile, def_u.first.skipped_ranges);
EmitSemanticHighlighting(db, semantic_cache, wfile,
EmitSemanticHighlighting(db, highlight, wfile,
&db->files[update->file_id]);
}
}
@ -460,7 +461,7 @@ void LaunchStdout() {
void MainLoop() {
Project project;
SemanticHighlightSymbolCache semantic_cache;
SemanticHighlight highlight;
WorkingFiles working_files;
VFS vfs;
DiagnosticsPublisher diag_pub;
@ -491,7 +492,7 @@ void MainLoop() {
handler->project = &project;
handler->diag_pub = &diag_pub;
handler->vfs = &vfs;
handler->semantic_cache = &semantic_cache;
handler->highlight = &highlight;
handler->working_files = &working_files;
handler->clang_complete = &clang_complete;
handler->include_complete = &include_complete;
@ -518,7 +519,7 @@ void MainLoop() {
if (!update)
break;
did_work = true;
Main_OnIndexed(&db, &semantic_cache, &working_files, &*update);
Main_OnIndexed(&db, &highlight, &working_files, &*update);
}
if (!did_work) {

View File

@ -11,6 +11,8 @@
#include "utils.h"
#include <llvm/Config/llvm-config.h>
#include <llvm/ADT/StringRef.h>
using namespace llvm;
#include <rapidjson/document.h>
#include <rapidjson/prettywriter.h>
@ -68,6 +70,12 @@ struct TextReplacer {
}
};
void TrimInPlace(std::string &s) {
auto f = [](char c) { return !isspace(c); };
s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
}
void ParseTestExpectation(
const std::string &filename,
const std::vector<std::string> &lines_with_endings, TextReplacer *replacer,
@ -77,7 +85,7 @@ void ParseTestExpectation(
{
bool in_output = false;
for (std::string line : lines_with_endings) {
TrimInPlace(line);
line = StringRef(line).trim().str();
if (StartsWith(line, "EXTRA_FLAGS:")) {
assert(!in_output && "multiple EXTRA_FLAGS sections");
@ -113,8 +121,7 @@ void ParseTestExpectation(
// one token assume it is a filename.
std::vector<std::string> tokens = SplitString(line_with_ending, " ");
if (tokens.size() > 1) {
active_output_filename = tokens[1];
TrimInPlace(active_output_filename);
active_output_filename = StringRef(tokens[1]).trim().str();
} else {
active_output_filename = filename;
}

View File

@ -21,16 +21,6 @@ using namespace llvm;
#include <string.h>
#include <unordered_map>
void TrimInPlace(std::string &s) {
auto f = [](char c) { return !isspace(c); };
s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
}
std::string Trim(std::string s) {
TrimInPlace(s);
return s;
}
uint64_t HashUsr(std::string_view s) {
union {
uint64_t ret;

View File

@ -16,9 +16,6 @@ namespace llvm {
class StringRef;
}
void TrimInPlace(std::string &s);
std::string Trim(std::string s);
uint64_t HashUsr(std::string_view s);
uint64_t HashUsr(llvm::StringRef s);