mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 15:45:08 +00:00
Simplify semantic highlighting
This commit is contained in:
parent
d9f0de4719
commit
28401961ae
@ -134,7 +134,7 @@ struct Config {
|
|||||||
// auto-completion. An example value is { ".h", ".hpp" }
|
// auto-completion. An example value is { ".h", ".hpp" }
|
||||||
//
|
//
|
||||||
// This is significantly faster than using a regex.
|
// 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;
|
std::vector<std::string> includeWhitelist;
|
||||||
} completion;
|
} completion;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "message_handler.h"
|
#include "message_handler.h"
|
||||||
|
|
||||||
#include "log.hh"
|
#include "log.hh"
|
||||||
|
#include "match.h"
|
||||||
#include "pipeline.hh"
|
#include "pipeline.hh"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "query_utils.h"
|
#include "query_utils.h"
|
||||||
@ -47,74 +48,34 @@ struct ScanLineEvent {
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SemanticHighlightSymbolCache::Entry::Entry(
|
int SemanticHighlight::GetStableId(SymbolKind kind, Usr usr) {
|
||||||
SemanticHighlightSymbolCache *all_caches, const std::string &path)
|
decltype(func2id) *map;
|
||||||
: 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) {
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SymbolKind::Type:
|
|
||||||
return &detailed_type_name_to_stable_id;
|
|
||||||
case SymbolKind::Func:
|
case SymbolKind::Func:
|
||||||
return &detailed_func_name_to_stable_id;
|
map = &func2id;
|
||||||
|
break;
|
||||||
|
case SymbolKind::Type:
|
||||||
|
map = &type2id;
|
||||||
|
break;
|
||||||
case SymbolKind::Var:
|
case SymbolKind::Var:
|
||||||
return &detailed_var_name_to_stable_id;
|
map = &var2id;
|
||||||
|
break;
|
||||||
case SymbolKind::File:
|
case SymbolKind::File:
|
||||||
case SymbolKind::Invalid:
|
case SymbolKind::Invalid:
|
||||||
break;
|
llvm_unreachable("");
|
||||||
}
|
}
|
||||||
assert(false);
|
|
||||||
return nullptr;
|
auto it = map->try_emplace(usr, next_id);
|
||||||
|
if (it.second)
|
||||||
|
next_id++;
|
||||||
|
return it.first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
SemanticHighlightSymbolCache::SemanticHighlightSymbolCache()
|
void SemanticHighlight::Init() {
|
||||||
: cache_(kCacheSize) {}
|
|
||||||
|
|
||||||
void SemanticHighlightSymbolCache::Init() {
|
|
||||||
match_ = std::make_unique<GroupMatch>(g_config->highlight.whitelist,
|
match_ = std::make_unique<GroupMatch>(g_config->highlight.whitelist,
|
||||||
g_config->highlight.blacklist);
|
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() {
|
MessageHandler::MessageHandler() {
|
||||||
// Dynamically allocate |message_handlers|, otherwise there will be static
|
// Dynamically allocate |message_handlers|, otherwise there will be static
|
||||||
// initialization order races.
|
// initialization order races.
|
||||||
@ -184,15 +145,12 @@ void EmitSkippedRanges(WorkingFile *working_file,
|
|||||||
pipeline::WriteStdout(kMethodType_CclsPublishSkippedRanges, out);
|
pipeline::WriteStdout(kMethodType_CclsPublishSkippedRanges, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSemanticHighlighting(DB *db,
|
void EmitSemanticHighlighting(DB *db, SemanticHighlight *highlight,
|
||||||
SemanticHighlightSymbolCache *semantic_cache,
|
|
||||||
WorkingFile *wfile, QueryFile *file) {
|
WorkingFile *wfile, QueryFile *file) {
|
||||||
assert(file->def);
|
assert(file->def);
|
||||||
if (wfile->buffer_content.size() > g_config->largeFileSize ||
|
if (wfile->buffer_content.size() > g_config->largeFileSize ||
|
||||||
!semantic_cache->match_->IsMatch(file->def->path))
|
!highlight->match_->IsMatch(file->def->path))
|
||||||
return;
|
return;
|
||||||
auto semantic_cache_for_file =
|
|
||||||
semantic_cache->GetCacheForFile(file->def->path);
|
|
||||||
|
|
||||||
// Group symbols together.
|
// Group symbols together.
|
||||||
std::unordered_map<SymbolIdx, Out_CclsPublishSemanticHighlighting::Symbol>
|
std::unordered_map<SymbolIdx, Out_CclsPublishSemanticHighlighting::Symbol>
|
||||||
@ -288,8 +246,7 @@ void EmitSemanticHighlighting(DB *db,
|
|||||||
it->second.lsRanges.push_back(*loc);
|
it->second.lsRanges.push_back(*loc);
|
||||||
} else {
|
} else {
|
||||||
Out_CclsPublishSemanticHighlighting::Symbol symbol;
|
Out_CclsPublishSemanticHighlighting::Symbol symbol;
|
||||||
symbol.stableId = semantic_cache_for_file->GetStableId(
|
symbol.stableId = highlight->GetStableId(sym.kind, sym.usr);
|
||||||
sym.kind, std::string(detailed_name));
|
|
||||||
symbol.parentKind = parent_kind;
|
symbol.parentKind = parent_kind;
|
||||||
symbol.kind = kind;
|
symbol.kind = kind;
|
||||||
symbol.storage = storage;
|
symbol.storage = storage;
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include "lru_cache.h"
|
#include "lru_cache.h"
|
||||||
#include "lsp.h"
|
#include "lsp.h"
|
||||||
#include "match.h"
|
|
||||||
#include "method.h"
|
#include "method.h"
|
||||||
#include "query.h"
|
#include "query.h"
|
||||||
|
|
||||||
@ -17,6 +16,7 @@
|
|||||||
struct CompletionManager;
|
struct CompletionManager;
|
||||||
struct Config;
|
struct Config;
|
||||||
class DiagnosticsPublisher;
|
class DiagnosticsPublisher;
|
||||||
|
struct GroupMatch;
|
||||||
struct VFS;
|
struct VFS;
|
||||||
struct IncludeComplete;
|
struct IncludeComplete;
|
||||||
struct MultiQueueWaiter;
|
struct MultiQueueWaiter;
|
||||||
@ -27,35 +27,13 @@ struct WorkingFiles;
|
|||||||
|
|
||||||
// Caches symbols for a single file for semantic highlighting to provide
|
// Caches symbols for a single file for semantic highlighting to provide
|
||||||
// relatively stable ids. Only supports xxx files at a time.
|
// relatively stable ids. Only supports xxx files at a time.
|
||||||
struct SemanticHighlightSymbolCache {
|
struct SemanticHighlight {
|
||||||
struct Entry {
|
llvm::DenseMap<Usr, int, DenseMapInfoForUsr> func2id, type2id, var2id;
|
||||||
SemanticHighlightSymbolCache *all_caches_ = nullptr;
|
uint32_t next_id = 0;
|
||||||
|
|
||||||
// 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;
|
|
||||||
std::unique_ptr<GroupMatch> match_;
|
std::unique_ptr<GroupMatch> match_;
|
||||||
|
|
||||||
SemanticHighlightSymbolCache();
|
|
||||||
void Init();
|
void Init();
|
||||||
std::shared_ptr<Entry> GetCacheForFile(const std::string &path);
|
int GetStableId(SymbolKind kind, Usr usr);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Out_CclsPublishSemanticHighlighting
|
struct Out_CclsPublishSemanticHighlighting
|
||||||
@ -102,7 +80,7 @@ struct MessageHandler {
|
|||||||
Project *project = nullptr;
|
Project *project = nullptr;
|
||||||
DiagnosticsPublisher *diag_pub = nullptr;
|
DiagnosticsPublisher *diag_pub = nullptr;
|
||||||
VFS *vfs = nullptr;
|
VFS *vfs = nullptr;
|
||||||
SemanticHighlightSymbolCache *semantic_cache = nullptr;
|
SemanticHighlight *highlight = nullptr;
|
||||||
WorkingFiles *working_files = nullptr;
|
WorkingFiles *working_files = nullptr;
|
||||||
CompletionManager *clang_complete = nullptr;
|
CompletionManager *clang_complete = nullptr;
|
||||||
IncludeComplete *include_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,
|
void EmitSkippedRanges(WorkingFile *working_file,
|
||||||
const std::vector<Range> &skipped_ranges);
|
const std::vector<Range> &skipped_ranges);
|
||||||
|
|
||||||
void EmitSemanticHighlighting(DB *db,
|
void EmitSemanticHighlighting(DB *db, SemanticHighlight *highlight,
|
||||||
SemanticHighlightSymbolCache *semantic_cache,
|
|
||||||
WorkingFile *working_file, QueryFile *file);
|
WorkingFile *working_file, QueryFile *file);
|
||||||
|
@ -476,7 +476,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
|||||||
|
|
||||||
diag_pub->Init();
|
diag_pub->Init();
|
||||||
idx::Init();
|
idx::Init();
|
||||||
semantic_cache->Init();
|
highlight->Init();
|
||||||
|
|
||||||
// Open up / load the project.
|
// Open up / load the project.
|
||||||
project->Load(project_path);
|
project->Load(project_path);
|
||||||
|
@ -48,7 +48,7 @@ struct Handler_TextDocumentDidOpen
|
|||||||
FindFileOrFail(db, project, std::nullopt, path, &file);
|
FindFileOrFail(db, project, std::nullopt, path, &file);
|
||||||
if (file && file->def) {
|
if (file && file->def) {
|
||||||
EmitSkippedRanges(working_file, file->def->skipped_ranges);
|
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);
|
include_complete->AddFile(working_file->filename);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "include_complete.h"
|
#include "include_complete.h"
|
||||||
#include "log.hh"
|
#include "log.hh"
|
||||||
#include "lsp.h"
|
#include "lsp.h"
|
||||||
|
#include "match.h"
|
||||||
#include "message_handler.h"
|
#include "message_handler.h"
|
||||||
#include "pipeline.hh"
|
#include "pipeline.hh"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
@ -358,7 +359,7 @@ void Indexer_Main(CompletionManager *completion, VFS *vfs, Project *project,
|
|||||||
indexer_waiter->Wait(index_request);
|
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) {
|
WorkingFiles *working_files, IndexUpdate *update) {
|
||||||
if (update->refresh) {
|
if (update->refresh) {
|
||||||
LOG_S(INFO)
|
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())
|
if (db->name2file_id.find(filename) == db->name2file_id.end())
|
||||||
continue;
|
continue;
|
||||||
QueryFile *file = &db->files[db->name2file_id[filename]];
|
QueryFile *file = &db->files[db->name2file_id[filename]];
|
||||||
EmitSemanticHighlighting(db, semantic_cache, f.get(), file);
|
EmitSemanticHighlighting(db, highlight, f.get(), file);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -389,7 +390,7 @@ void Main_OnIndexed(DB *db, SemanticHighlightSymbolCache *semantic_cache,
|
|||||||
wfile->SetIndexContent(g_config->index.onChange ? wfile->buffer_content
|
wfile->SetIndexContent(g_config->index.onChange ? wfile->buffer_content
|
||||||
: def_u.second);
|
: def_u.second);
|
||||||
EmitSkippedRanges(wfile, def_u.first.skipped_ranges);
|
EmitSkippedRanges(wfile, def_u.first.skipped_ranges);
|
||||||
EmitSemanticHighlighting(db, semantic_cache, wfile,
|
EmitSemanticHighlighting(db, highlight, wfile,
|
||||||
&db->files[update->file_id]);
|
&db->files[update->file_id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,7 +461,7 @@ void LaunchStdout() {
|
|||||||
|
|
||||||
void MainLoop() {
|
void MainLoop() {
|
||||||
Project project;
|
Project project;
|
||||||
SemanticHighlightSymbolCache semantic_cache;
|
SemanticHighlight highlight;
|
||||||
WorkingFiles working_files;
|
WorkingFiles working_files;
|
||||||
VFS vfs;
|
VFS vfs;
|
||||||
DiagnosticsPublisher diag_pub;
|
DiagnosticsPublisher diag_pub;
|
||||||
@ -491,7 +492,7 @@ void MainLoop() {
|
|||||||
handler->project = &project;
|
handler->project = &project;
|
||||||
handler->diag_pub = &diag_pub;
|
handler->diag_pub = &diag_pub;
|
||||||
handler->vfs = &vfs;
|
handler->vfs = &vfs;
|
||||||
handler->semantic_cache = &semantic_cache;
|
handler->highlight = &highlight;
|
||||||
handler->working_files = &working_files;
|
handler->working_files = &working_files;
|
||||||
handler->clang_complete = &clang_complete;
|
handler->clang_complete = &clang_complete;
|
||||||
handler->include_complete = &include_complete;
|
handler->include_complete = &include_complete;
|
||||||
@ -518,7 +519,7 @@ void MainLoop() {
|
|||||||
if (!update)
|
if (!update)
|
||||||
break;
|
break;
|
||||||
did_work = true;
|
did_work = true;
|
||||||
Main_OnIndexed(&db, &semantic_cache, &working_files, &*update);
|
Main_OnIndexed(&db, &highlight, &working_files, &*update);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!did_work) {
|
if (!did_work) {
|
||||||
|
13
src/test.cc
13
src/test.cc
@ -11,6 +11,8 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include <llvm/Config/llvm-config.h>
|
#include <llvm/Config/llvm-config.h>
|
||||||
|
#include <llvm/ADT/StringRef.h>
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
#include <rapidjson/document.h>
|
#include <rapidjson/document.h>
|
||||||
#include <rapidjson/prettywriter.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(
|
void ParseTestExpectation(
|
||||||
const std::string &filename,
|
const std::string &filename,
|
||||||
const std::vector<std::string> &lines_with_endings, TextReplacer *replacer,
|
const std::vector<std::string> &lines_with_endings, TextReplacer *replacer,
|
||||||
@ -77,7 +85,7 @@ void ParseTestExpectation(
|
|||||||
{
|
{
|
||||||
bool in_output = false;
|
bool in_output = false;
|
||||||
for (std::string line : lines_with_endings) {
|
for (std::string line : lines_with_endings) {
|
||||||
TrimInPlace(line);
|
line = StringRef(line).trim().str();
|
||||||
|
|
||||||
if (StartsWith(line, "EXTRA_FLAGS:")) {
|
if (StartsWith(line, "EXTRA_FLAGS:")) {
|
||||||
assert(!in_output && "multiple EXTRA_FLAGS sections");
|
assert(!in_output && "multiple EXTRA_FLAGS sections");
|
||||||
@ -113,8 +121,7 @@ void ParseTestExpectation(
|
|||||||
// one token assume it is a filename.
|
// one token assume it is a filename.
|
||||||
std::vector<std::string> tokens = SplitString(line_with_ending, " ");
|
std::vector<std::string> tokens = SplitString(line_with_ending, " ");
|
||||||
if (tokens.size() > 1) {
|
if (tokens.size() > 1) {
|
||||||
active_output_filename = tokens[1];
|
active_output_filename = StringRef(tokens[1]).trim().str();
|
||||||
TrimInPlace(active_output_filename);
|
|
||||||
} else {
|
} else {
|
||||||
active_output_filename = filename;
|
active_output_filename = filename;
|
||||||
}
|
}
|
||||||
|
10
src/utils.cc
10
src/utils.cc
@ -21,16 +21,6 @@ using namespace llvm;
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unordered_map>
|
#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) {
|
uint64_t HashUsr(std::string_view s) {
|
||||||
union {
|
union {
|
||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
|
@ -16,9 +16,6 @@ namespace llvm {
|
|||||||
class StringRef;
|
class StringRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrimInPlace(std::string &s);
|
|
||||||
std::string Trim(std::string s);
|
|
||||||
|
|
||||||
uint64_t HashUsr(std::string_view s);
|
uint64_t HashUsr(std::string_view s);
|
||||||
uint64_t HashUsr(llvm::StringRef s);
|
uint64_t HashUsr(llvm::StringRef s);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user