From d816e1b9188cb43b50d1c19bf853dd3d9ddbfe3a Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 8 Jul 2018 19:56:33 -0700 Subject: [PATCH] $ccls/publishSemanticHighlighting: use pair in place of lsRange --- src/indexer.cc | 4 +- src/message_handler.cc | 264 +++++++++++++++++++++++------------------ src/message_handler.h | 5 +- 3 files changed, 153 insertions(+), 120 deletions(-) diff --git a/src/indexer.cc b/src/indexer.cc index 0764112a..35cc9ac0 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -531,11 +531,13 @@ public: off |= 1u << 31; Loc = SourceLocation::getFromRawEncoding(off); } +#else + FileID LocFID; #endif SourceLocation Spell = SM.getSpellingLoc(Loc); Loc = SM.getFileLoc(Loc); Range loc = FromTokenRange(SM, Lang, SourceRange(Loc, Loc)); - FileID LocFID = SM.getFileID(Loc); + LocFID = SM.getFileID(Loc); const FileEntry *FE = SM.getFileEntryForID(LocFID); if (!FE) { // TODO diff --git a/src/message_handler.cc b/src/message_handler.cc index a30ef685..60e74b59 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -1,9 +1,9 @@ #include "message_handler.h" #include "log.hh" +#include "pipeline.hh" #include "project.h" #include "query_utils.h" -#include "pipeline.hh" using namespace ccls; using namespace clang; @@ -28,10 +28,10 @@ MAKE_REFLECT_STRUCT(Out_CclsSetSkippedRanges, jsonrpc, method, params); struct ScanLineEvent { lsPosition pos; - lsPosition end_pos; // Second key when there is a tie for insertion events. + lsPosition end_pos; // Second key when there is a tie for insertion events. int id; - Out_CclsPublishSemanticHighlighting::Symbol* symbol; - bool operator<(const ScanLineEvent& other) const { + Out_CclsPublishSemanticHighlighting::Symbol *symbol; + bool operator<(const ScanLineEvent &other) const { // See the comments below when insertion/deletion events are inserted. if (!(pos == other.pos)) return pos < other.pos; @@ -42,17 +42,15 @@ struct ScanLineEvent { return symbol->kind < other.symbol->kind; } }; -} // namespace +} // namespace SemanticHighlightSymbolCache::Entry::Entry( - SemanticHighlightSymbolCache* all_caches, - const std::string& path) + SemanticHighlightSymbolCache *all_caches, const std::string &path) : all_caches_(all_caches), path(path) {} std::optional SemanticHighlightSymbolCache::Entry::TryGetStableId( - SymbolKind kind, - const std::string& detailed_name) { - TNameToId* map = GetMapForSymbol_(kind); + SymbolKind kind, const std::string &detailed_name) { + TNameToId *map = GetMapForSymbol_(kind); auto it = map->find(detailed_name); if (it != map->end()) return it->second; @@ -61,14 +59,13 @@ std::optional SemanticHighlightSymbolCache::Entry::TryGetStableId( } int SemanticHighlightSymbolCache::Entry::GetStableId( - SymbolKind kind, - const std::string& detailed_name) { + SymbolKind kind, const std::string &detailed_name) { std::optional 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) { + all_caches_->cache_.IterateValues([&](const std::shared_ptr &entry) { std::optional other_id = entry->TryGetStableId(kind, detailed_name); if (other_id) { id = other_id; @@ -78,24 +75,24 @@ int SemanticHighlightSymbolCache::Entry::GetStableId( }); // Create a new id. - TNameToId* map = GetMapForSymbol_(kind); + TNameToId *map = GetMapForSymbol_(kind); if (!id) id = all_caches_->next_stable_id_++; return (*map)[detailed_name] = *id; } -SemanticHighlightSymbolCache::Entry::TNameToId* +SemanticHighlightSymbolCache::Entry::TNameToId * SemanticHighlightSymbolCache::Entry::GetMapForSymbol_(SymbolKind kind) { switch (kind) { - case SymbolKind::Type: - return &detailed_type_name_to_stable_id; - case SymbolKind::Func: - return &detailed_func_name_to_stable_id; - case SymbolKind::Var: - return &detailed_var_name_to_stable_id; - case SymbolKind::File: - case SymbolKind::Invalid: - break; + case SymbolKind::Type: + return &detailed_type_name_to_stable_id; + case SymbolKind::Func: + return &detailed_func_name_to_stable_id; + case SymbolKind::Var: + return &detailed_var_name_to_stable_id; + case SymbolKind::File: + case SymbolKind::Invalid: + break; } assert(false); return nullptr; @@ -110,7 +107,7 @@ void SemanticHighlightSymbolCache::Init() { } std::shared_ptr -SemanticHighlightSymbolCache::GetCacheForFile(const std::string& path) { +SemanticHighlightSymbolCache::GetCacheForFile(const std::string &path) { return cache_.Get( path, [&, this]() { return std::make_shared(this, path); }); } @@ -119,24 +116,21 @@ MessageHandler::MessageHandler() { // Dynamically allocate |message_handlers|, otherwise there will be static // initialization order races. if (!message_handlers) - message_handlers = new std::vector(); + message_handlers = new std::vector(); message_handlers->push_back(this); } // static -std::vector* MessageHandler::message_handlers = nullptr; - -bool FindFileOrFail(DB* db, - Project* project, - std::optional id, - const std::string& absolute_path, - QueryFile** out_query_file, - int* out_file_id) { +std::vector *MessageHandler::message_handlers = nullptr; + +bool FindFileOrFail(DB *db, Project *project, std::optional id, + const std::string &absolute_path, + QueryFile **out_query_file, int *out_file_id) { *out_query_file = nullptr; auto it = db->name2file_id.find(LowerPathIfInsensitive(absolute_path)); if (it != db->name2file_id.end()) { - QueryFile& file = db->files[it->second]; + QueryFile &file = db->files[it->second]; if (file.def) { *out_query_file = &file; if (out_file_id) @@ -152,7 +146,7 @@ bool FindFileOrFail(DB* db, { std::lock_guard lock(project->mutex_); indexing = project->absolute_path_to_entry_index_.find(absolute_path) != - project->absolute_path_to_entry_index_.end(); + project->absolute_path_to_entry_index_.end(); } if (indexing) LOG_S(INFO) << "\"" << absolute_path << "\" is being indexed."; @@ -187,10 +181,9 @@ void EmitSkippedRanges(WorkingFile *working_file, pipeline::WriteStdout(kMethodType_CclsPublishSkippedRanges, out); } -void EmitSemanticHighlighting(DB* db, - SemanticHighlightSymbolCache* semantic_cache, - WorkingFile* wfile, - QueryFile* file) { +void EmitSemanticHighlighting(DB *db, + SemanticHighlightSymbolCache *semantic_cache, + WorkingFile *wfile, QueryFile *file) { assert(file->def); if (wfile->buffer_content.size() > g_config->largeFileSize || !semantic_cache->match_->IsMatch(file->def->path)) @@ -208,86 +201,86 @@ void EmitSemanticHighlighting(DB* db, StorageClass storage = SC_None; // This switch statement also filters out symbols that are not highlighted. switch (sym.kind) { - case SymbolKind::Func: { - const QueryFunc& func = db->GetFunc(sym); - const QueryFunc::Def* def = func.AnyDef(); - if (!def) - continue; // applies to for loop - if (def->spell) - parent_kind = GetSymbolKind(db, *def->spell); - if (parent_kind == lsSymbolKind::Unknown) { - for (Use use : func.declarations) { - parent_kind = GetSymbolKind(db, use); - break; - } + case SymbolKind::Func: { + const QueryFunc &func = db->GetFunc(sym); + const QueryFunc::Def *def = func.AnyDef(); + if (!def) + continue; // applies to for loop + if (def->spell) + parent_kind = GetSymbolKind(db, *def->spell); + if (parent_kind == lsSymbolKind::Unknown) { + for (Use use : func.declarations) { + parent_kind = GetSymbolKind(db, use); + break; } - // Don't highlight overloadable operators or implicit lambda -> - // std::function constructor. - std::string_view short_name = def->Name(false); - if (short_name.compare(0, 8, "operator") == 0) - continue; // applies to for loop - if (def->spell) - parent_kind = GetSymbolKind(db, *def->spell); - kind = def->kind; - storage = def->storage; - detailed_name = short_name; - - // Check whether the function name is actually there. - // If not, do not publish the semantic highlight. - // E.g. copy-initialization of constructors should not be highlighted - // but we still want to keep the range for jumping to definition. - std::string_view concise_name = - detailed_name.substr(0, detailed_name.find('<')); - int16_t start_line = sym.range.start.line; - int16_t start_col = sym.range.start.column; - if (start_line < 0 || start_line >= wfile->index_lines.size()) - continue; - std::string_view line = wfile->index_lines[start_line]; - sym.range.end.line = start_line; - if (!(start_col + concise_name.size() <= line.size() && - line.compare(start_col, concise_name.size(), concise_name) == 0)) - continue; - sym.range.end.column = start_col + concise_name.size(); - break; } - case SymbolKind::Type: - for (auto& def : db->GetType(sym).def) { - kind = def.kind; - detailed_name = def.detailed_name; - if (def.spell) { - parent_kind = GetSymbolKind(db, *def.spell); - break; - } + // Don't highlight overloadable operators or implicit lambda -> + // std::function constructor. + std::string_view short_name = def->Name(false); + if (short_name.compare(0, 8, "operator") == 0) + continue; // applies to for loop + if (def->spell) + parent_kind = GetSymbolKind(db, *def->spell); + kind = def->kind; + storage = def->storage; + detailed_name = short_name; + + // Check whether the function name is actually there. + // If not, do not publish the semantic highlight. + // E.g. copy-initialization of constructors should not be highlighted + // but we still want to keep the range for jumping to definition. + std::string_view concise_name = + detailed_name.substr(0, detailed_name.find('<')); + int16_t start_line = sym.range.start.line; + int16_t start_col = sym.range.start.column; + if (start_line < 0 || start_line >= wfile->index_lines.size()) + continue; + std::string_view line = wfile->index_lines[start_line]; + sym.range.end.line = start_line; + if (!(start_col + concise_name.size() <= line.size() && + line.compare(start_col, concise_name.size(), concise_name) == 0)) + continue; + sym.range.end.column = start_col + concise_name.size(); + break; + } + case SymbolKind::Type: + for (auto &def : db->GetType(sym).def) { + kind = def.kind; + detailed_name = def.detailed_name; + if (def.spell) { + parent_kind = GetSymbolKind(db, *def.spell); + break; } - break; - case SymbolKind::Var: { - const QueryVar& var = db->GetVar(sym); - for (auto& def : var.def) { - kind = def.kind; - storage = def.storage; - detailed_name = def.detailed_name; - if (def.spell) { - parent_kind = GetSymbolKind(db, *def.spell); - break; - } + } + break; + case SymbolKind::Var: { + const QueryVar &var = db->GetVar(sym); + for (auto &def : var.def) { + kind = def.kind; + storage = def.storage; + detailed_name = def.detailed_name; + if (def.spell) { + parent_kind = GetSymbolKind(db, *def.spell); + break; } - if (parent_kind == lsSymbolKind::Unknown) { - for (Use use : var.declarations) { - parent_kind = GetSymbolKind(db, use); - break; - } + } + if (parent_kind == lsSymbolKind::Unknown) { + for (Use use : var.declarations) { + parent_kind = GetSymbolKind(db, use); + break; } - break; } - default: - continue; // applies to for loop + break; + } + default: + continue; // applies to for loop } std::optional loc = GetLsRange(wfile, sym.range); if (loc) { auto it = grouped_symbols.find(sym); if (it != grouped_symbols.end()) { - it->second.ranges.push_back(*loc); + it->second.lsRanges.push_back(*loc); } else { Out_CclsPublishSemanticHighlighting::Symbol symbol; symbol.stableId = semantic_cache_for_file->GetStableId( @@ -295,7 +288,7 @@ void EmitSemanticHighlighting(DB* db, symbol.parentKind = parent_kind; symbol.kind = kind; symbol.storage = storage; - symbol.ranges.push_back(*loc); + symbol.lsRanges.push_back(*loc); grouped_symbols[sym] = symbol; } } @@ -304,9 +297,9 @@ void EmitSemanticHighlighting(DB* db, // Make ranges non-overlapping using a scan line algorithm. std::vector events; int id = 0; - for (auto& entry : grouped_symbols) { - Out_CclsPublishSemanticHighlighting::Symbol& symbol = entry.second; - for (auto& loc : symbol.ranges) { + for (auto &entry : grouped_symbols) { + Out_CclsPublishSemanticHighlighting::Symbol &symbol = entry.second; + for (auto &loc : symbol.lsRanges) { // For ranges sharing the same start point, the one with leftmost end // point comes first. events.push_back({loc.start, loc.end, id, &symbol}); @@ -316,7 +309,7 @@ void EmitSemanticHighlighting(DB* db, events.push_back({loc.end, loc.end, ~id, &symbol}); id++; } - symbol.ranges.clear(); + symbol.lsRanges.clear(); } std::sort(events.begin(), events.end()); @@ -332,19 +325,54 @@ void EmitSemanticHighlighting(DB* db, // Attribute range [events[i-1].pos, events[i].pos) to events[top-1].symbol // . if (top && !(events[i - 1].pos == events[i].pos)) - events[top - 1].symbol->ranges.push_back( - lsRange{events[i - 1].pos, events[i].pos}); + events[top - 1].symbol->lsRanges.push_back( + {events[i - 1].pos, events[i].pos}); if (events[i].id >= 0) events[top++] = events[i]; else deleted[~events[i].id] = 1; } - // Publish. Out_CclsPublishSemanticHighlighting out; out.params.uri = lsDocumentUri::FromPath(wfile->filename); - for (auto& entry : grouped_symbols) + // Transform lsRange into pair (offset pairs) + { + std::vector> + scratch; + for (auto &entry : grouped_symbols) + for (auto &range : entry.second.lsRanges) + scratch.emplace_back(range, &entry.second); + std::sort(scratch.begin(), scratch.end(), + [](auto &l, auto &r) { return l.first.start < r.first.start; }); + const auto &buf = wfile->buffer_content; + int l = 0, c = 0, i = 0; + auto mov = [&](int line, int col) { + if (l < line) + c = 0; + for (; l < line && i < buf.size(); i++) + if (buf[i] == '\n') + l++; + if (l < line) return true; + for (; c < col && i < buf.size(); c++) + if (uint8_t(buf[i++]) >= 128) + // Skip 0b10xxxxxx + while (i < buf.size() && uint8_t(buf[i]) >= 128 && uint8_t(buf[i]) < 192) + i++; + return c < col; + }; + for (auto &entry : scratch) { + lsRange &r = entry.first; + if (mov(r.start.line, r.start.character)) + continue; + int beg = i; + if (mov(r.end.line, r.end.character)) + continue; + entry.second->ranges.emplace_back(beg, i); + } + } + + for (auto &entry : grouped_symbols) if (entry.second.ranges.size()) - out.params.symbols.push_back(entry.second); + out.params.symbols.push_back(std::move(entry.second)); pipeline::WriteStdout(kMethodType_CclsPublishSemanticHighlighting, out); } diff --git a/src/message_handler.h b/src/message_handler.h index 6b6daa6c..425a134d 100644 --- a/src/message_handler.h +++ b/src/message_handler.h @@ -64,7 +64,10 @@ struct Out_CclsPublishSemanticHighlighting lsSymbolKind parentKind; lsSymbolKind kind; clang::StorageClass storage; - std::vector ranges; + std::vector> ranges; + + // `lsRanges` is used to compute `ranges`. + std::vector lsRanges; }; struct Params { lsDocumentUri uri;