diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e829ca7..b35acd4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,6 @@ target_sources(ccls PRIVATE src/clang_tu.cc src/clang_utils.cc src/config.cc - src/diagnostics_publisher.cc src/file_consumer.cc src/filesystem.cc src/fuzzy_match.cc diff --git a/src/clang_tu.cc b/src/clang_tu.cc index dbb1d89d..8b5b1450 100644 --- a/src/clang_tu.cc +++ b/src/clang_tu.cc @@ -259,7 +259,7 @@ std::string ClangCursor::get_type_description() const { return ::ToString(clang_getTypeSpelling(type)); } -NtString ClangCursor::get_comments() const { +std::string ClangCursor::get_comments() const { CXSourceRange range = clang_Cursor_getCommentRange(cx_cursor); if (clang_Range_isNull(range)) return {}; @@ -317,7 +317,7 @@ NtString ClangCursor::get_comments() const { ret.pop_back(); if (ret.empty()) return {}; - return static_cast(ret); + return ret; } std::string ClangCursor::ToString() const { diff --git a/src/clang_tu.h b/src/clang_tu.h index 2530b2de..85bbf537 100644 --- a/src/clang_tu.h +++ b/src/clang_tu.h @@ -1,5 +1,4 @@ #pragma once -#include "nt_string.h" #include "position.h" #include @@ -86,7 +85,7 @@ class ClangCursor { bool is_valid_kind() const; std::string get_type_description() const; - NtString get_comments() const; + std::string get_comments() const; std::string ToString() const; diff --git a/src/diagnostics_publisher.cc b/src/diagnostics_publisher.cc deleted file mode 100644 index 6402d98c..00000000 --- a/src/diagnostics_publisher.cc +++ /dev/null @@ -1,36 +0,0 @@ -#include "diagnostics_publisher.hh" - -#include "pipeline.hh" -using namespace ccls; - -#include - -void DiagnosticsPublisher::Init() { - frequencyMs_ = g_config->diagnostics.frequencyMs; - match_ = std::make_unique(g_config->diagnostics.whitelist, - g_config->diagnostics.blacklist); -} - -void DiagnosticsPublisher::Publish(WorkingFiles* working_files, - std::string path, - std::vector diagnostics) { - // Cache diagnostics so we can show fixits. - working_files->DoActionOnFile(path, [&](WorkingFile* working_file) { - if (working_file) - working_file->diagnostics_ = diagnostics; - }); - - int64_t now = - std::chrono::duration_cast( - std::chrono::high_resolution_clock::now().time_since_epoch()) - .count(); - if (frequencyMs_ >= 0 && (nextPublish_ <= now || diagnostics.empty()) && - match_->IsMatch(path)) { - nextPublish_ = now + frequencyMs_; - - Out_TextDocumentPublishDiagnostics out; - out.params.uri = lsDocumentUri::FromPath(path); - out.params.diagnostics = diagnostics; - pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out); - } -} diff --git a/src/diagnostics_publisher.hh b/src/diagnostics_publisher.hh deleted file mode 100644 index a6b5a688..00000000 --- a/src/diagnostics_publisher.hh +++ /dev/null @@ -1,16 +0,0 @@ -#include "lsp_diagnostic.h" - -#include "match.h" -#include "working_files.h" - -class DiagnosticsPublisher { - std::unique_ptr match_; - int64_t nextPublish_ = 0; - int frequencyMs_; - - public: - void Init(); - void Publish(WorkingFiles* working_files, - std::string path, - std::vector diagnostics); -}; diff --git a/src/indexer.cc b/src/indexer.cc index 7e305b78..1e5720b9 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -3,6 +3,7 @@ #include "log.hh" #include "platform.h" #include "serializer.h" +using ccls::Intern; #include #include @@ -523,8 +524,10 @@ void SetTypeName(IndexType& type, // ns {}` which are not qualified. // type->def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor); int short_name_offset, short_name_size; - std::tie(type.def.detailed_name, short_name_offset, short_name_size) = + std::string detailed; + std::tie(detailed, short_name_offset, short_name_size) = param->ns.QualifiedName(container ? container : &parent, name); + type.def.detailed_name = Intern(detailed); type.def.qual_name_offset = 0; type.def.short_name_offset = short_name_offset; type.def.short_name_size = short_name_size; @@ -558,7 +561,7 @@ IndexType* ResolveToDeclarationType(IndexFile* db, if (!usr) return nullptr; IndexType& typ = db->ToType(*usr); - if (typ.def.detailed_name.empty()) { + if (!typ.def.detailed_name[0]) { std::string name = declaration.get_spell_name(); SetTypeName(typ, declaration, nullptr, name.c_str(), param); } @@ -580,7 +583,7 @@ void SetVarDetail(IndexVar& var, if (type_name.find("(lambda at") != std::string::npos) type_name = "lambda"; if (g_config->index.comments) - def.comments = cursor.get_comments(); + def.comments = Intern(cursor.get_comments()); def.storage = GetStorageC(clang_Cursor_getStorageClass(cursor.cx_cursor)); // TODO how to make PrettyPrint'ed variable name qualified? @@ -607,16 +610,16 @@ void SetVarDetail(IndexVar& var, else hover += std::to_string(TD->getInitVal().getSExtValue()); } - def.detailed_name = std::move(qualified_name); + def.detailed_name = Intern(qualified_name); def.qual_name_offset = 0; - def.hover = hover; + def.hover = Intern(hover); } else { #if 0 def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor, false); #else int offset = type_name.size(); offset += ConcatTypeAndName(type_name, qualified_name); - def.detailed_name = type_name; + def.detailed_name = Intern(type_name); def.qual_name_offset = offset; def.short_name_offset += offset; // Append the textual initializer, bit field, constructor to |hover|. @@ -663,8 +666,9 @@ void SetVarDetail(IndexVar& var, std::optional spell_end = fc.ToOffset(spell_p), extent_end = fc.ToOffset(extent_p); if (extent_end && *spell_end < *extent_end) - def.hover = std::string(def.detailed_name.c_str()) + - fc.content.substr(*spell_end, *extent_end - *spell_end); + def.hover = + Intern(std::string(def.detailed_name) + + fc.content.substr(*spell_end, *extent_end - *spell_end)); } } skip:; @@ -714,7 +718,7 @@ void OnIndexReference_Function(IndexFile* db, // static const int IndexFile::kMajorVersion = 16; -const int IndexFile::kMinorVersion = 0; +const int IndexFile::kMinorVersion = 1; IndexFile::IndexFile(const std::string& path, const std::string& contents) : path(path), file_contents(contents) {} @@ -741,7 +745,7 @@ IndexVar& IndexFile::ToVar(Usr usr) { } std::string IndexFile::ToString() { - return Serialize(SerializeFormat::Json, *this); + return ccls::Serialize(SerializeFormat::Json, *this); } void Uniquify(std::vector& usrs) { @@ -1197,16 +1201,17 @@ ClangCursor::VisitResult VisitMacroDefinitionAndExpansions(ClangCursor cursor, IndexVar& var_def = db->ToVar(decl_usr); if (cursor.get_kind() == CXCursor_MacroDefinition) { CXSourceRange cx_extent = clang_getCursorExtent(cursor.cx_cursor); - var_def.def.detailed_name = cursor.get_display_name(); + var_def.def.detailed_name = Intern(cursor.get_display_name()); var_def.def.qual_name_offset = 0; var_def.def.short_name_offset = 0; var_def.def.short_name_size = - int16_t(strlen(var_def.def.detailed_name.c_str())); + int16_t(strlen(var_def.def.detailed_name)); var_def.def.hover = - "#define " + GetDocumentContentInRange(param->tu->cx_tu, cx_extent); + Intern("#define " + + GetDocumentContentInRange(param->tu->cx_tu, cx_extent)); var_def.def.kind = lsSymbolKind::Macro; if (g_config->index.comments) - var_def.def.comments = cursor.get_comments(); + var_def.def.comments = Intern(cursor.get_comments()); var_def.def.spell = SetUse(db, decl_loc_spelling, parent, Role::Definition); var_def.def.extent = SetUse( @@ -1244,7 +1249,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, ClangCursor ref_cursor = clang_getCursorReferenced(cursor.cx_cursor); if (ref_cursor.get_kind() == CXCursor_NonTypeTemplateParameter) { IndexVar& ref_var = db->ToVar(ref_cursor); - if (ref_var.def.detailed_name.empty()) { + if (!ref_var.def.detailed_name[0]) { ClangCursor sem_parent = ref_cursor.get_semantic_parent(); ClangCursor lex_parent = ref_cursor.get_lexical_parent(); ref_var.def.spell = @@ -1298,7 +1303,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, // CXCursor_TemplateTemplateParameter can be visited by visiting // CXCursor_TranslationUnit, but not (confirm this) by visiting // {Class,Function}Template. Thus we need to initialize it here. - if (ref_type.def.detailed_name.empty()) { + if (!ref_type.def.detailed_name[0]) { ClangCursor sem_parent = ref_cursor.get_semantic_parent(); ClangCursor lex_parent = ref_cursor.get_lexical_parent(); ref_type.def.spell = @@ -1308,11 +1313,11 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, #if 0 && CINDEX_HAVE_PRETTY ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor); #else - ref_type.def.detailed_name = ref_cursor.get_spell_name(); + ref_type.def.detailed_name = Intern(ref_cursor.get_spell_name()); #endif ref_type.def.short_name_offset = 0; ref_type.def.short_name_size = - int16_t(strlen(ref_type.def.detailed_name.c_str())); + int16_t(strlen(ref_type.def.detailed_name)); ref_type.def.kind = lsSymbolKind::TypeParameter; } AddUseSpell(db, ref_type.uses, cursor); @@ -1328,7 +1333,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, // CXCursor_TemplateTypeParameter can be visited by visiting // CXCursor_TranslationUnit, but not (confirm this) by visiting // {Class,Function}Template. Thus we need to initialize it here. - if (ref_type.def.detailed_name.empty()) { + if (!ref_type.def.detailed_name[0]) { ClangCursor sem_parent = ref_cursor.get_semantic_parent(); ClangCursor lex_parent = ref_cursor.get_lexical_parent(); ref_type.def.spell = @@ -1339,11 +1344,11 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, // template void f(T t){} // weird, the name is empty ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor); #else - ref_type.def.detailed_name = ref_cursor.get_spell_name(); + ref_type.def.detailed_name = Intern(ref_cursor.get_spell_name()); #endif ref_type.def.short_name_offset = 0; ref_type.def.short_name_size = - int16_t(strlen(ref_type.def.detailed_name.c_str())); + int16_t(strlen(ref_type.def.detailed_name)); ref_type.def.kind = lsSymbolKind::TypeParameter; } AddUseSpell(db, ref_type.uses, cursor); @@ -1443,7 +1448,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { Range spell = cursor.get_spell(); IndexType& ns = db->ToType(HashUsr(decl->entityInfo->USR)); ns.def.kind = GetSymbolKind(decl->entityInfo->kind); - if (ns.def.detailed_name.empty()) { + if (!ns.def.detailed_name[0]) { SetTypeName(ns, cursor, decl->semanticContainer, decl->entityInfo->name, param); ns.def.spell = SetUse(db, spell, sem_parent, Role::Definition); @@ -1559,7 +1564,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { IndexFunc& func = db->ToFunc(decl_cursor_resolved); if (g_config->index.comments) - func.def.comments = cursor.get_comments(); + func.def.comments = Intern(cursor.get_comments()); func.def.kind = GetSymbolKind(decl->entityInfo->kind); func.def.storage = GetStorageC(clang_Cursor_getStorageClass(decl->cursor)); @@ -1592,9 +1597,11 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { // indexing the definition, then there will not be any (ie) outline // information. if (!is_template_specialization) { - std::tie(func.def.detailed_name, func.def.qual_name_offset, + std::string detailed; + std::tie(detailed, func.def.qual_name_offset, func.def.short_name_offset, func.def.short_name_size) = param->PrettyPrintCursor(decl->cursor, decl->entityInfo->name); + func.def.detailed_name = Intern(detailed); // CXCursor_OverloadedDeclRef in templates are not processed by // OnIndexReference, thus we use TemplateVisitor to collect function @@ -1668,7 +1675,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { decl->entityInfo->name, param); type.def.kind = GetSymbolKind(decl->entityInfo->kind); if (g_config->index.comments) - type.def.comments = cursor.get_comments(); + type.def.comments = Intern(cursor.get_comments()); // For Typedef/CXXTypeAlias spanning a few lines, display the declaration // line, with spelling name replaced with qualified name. @@ -1679,10 +1686,10 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { spell_end = fc.ToOffset(spell.end), extent_end = fc.ToOffset(extent.end); if (extent_start && spell_start && spell_end && extent_end) { - type.def.hover = + type.def.hover = Intern( fc.content.substr(*extent_start, *spell_start - *extent_start) + - type.def.detailed_name.c_str() + - fc.content.substr(*spell_end, *extent_end - *spell_end); + type.def.detailed_name + + fc.content.substr(*spell_end, *extent_end - *spell_end)); } } @@ -1711,7 +1718,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { param); type.def.kind = GetSymbolKind(decl->entityInfo->kind); if (g_config->index.comments) - type.def.comments = cursor.get_comments(); + type.def.comments = Intern(cursor.get_comments()); // } if (decl->isDefinition) { @@ -1743,7 +1750,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { // template class function; // not visited by // OnIndexDeclaration template<> class function {}; // current // cursor - if (origin.def.detailed_name.empty()) { + if (!origin.def.detailed_name[0]) { SetTypeName(origin, origin_cursor, nullptr, &type.def.Name(false)[0], param); origin.def.kind = type.def.kind; @@ -1895,7 +1902,7 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { // may not have a short_name yet. Note that we only process the lambda // parameter as a definition if it is in the same file as the reference, // as lambdas cannot be split across files. - if (var.def.detailed_name.empty()) { + if (!var.def.detailed_name[0]) { CXFile referenced_file; Range spell = referenced.get_spell(&referenced_file); if (file == referenced_file) { diff --git a/src/indexer.h b/src/indexer.h index 156f7c66..b7f06e15 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -6,7 +6,6 @@ #include "language.h" #include "lsp.h" #include "maybe.h" -#include "nt_string.h" #include "position.h" #include "serializer.h" #include "symbol.h" @@ -69,21 +68,21 @@ template struct NameMixin { std::string_view Name(bool qualified) const { auto self = static_cast(this); - return qualified ? std::string_view( - self->detailed_name.c_str() + self->qual_name_offset, - self->short_name_offset - self->qual_name_offset + - self->short_name_size) - : std::string_view(self->detailed_name.c_str() + - self->short_name_offset, - self->short_name_size); + return qualified + ? std::string_view(self->detailed_name + self->qual_name_offset, + self->short_name_offset - + self->qual_name_offset + + self->short_name_size) + : std::string_view(self->detailed_name + self->short_name_offset, + self->short_name_size); } }; struct FuncDef : NameMixin { // General metadata. - std::string detailed_name; - NtString hover; - NtString comments; + const char* detailed_name = ""; + const char* hover = ""; + const char* comments = ""; Maybe spell; Maybe extent; @@ -105,13 +104,6 @@ struct FuncDef : NameMixin { clang::StorageClass storage = clang::SC_None; std::vector GetBases() const { return bases; } - bool operator==(const FuncDef& o) const { - return detailed_name == o.detailed_name && spell == o.spell && - extent == o.extent && declaring_type == o.declaring_type && - bases == o.bases && vars == o.vars && callees == o.callees && - kind == o.kind && storage == o.storage && hover == o.hover && - comments == o.comments; - } }; MAKE_REFLECT_STRUCT(FuncDef, detailed_name, @@ -139,10 +131,9 @@ struct IndexFunc : NameMixin { }; struct TypeDef : NameMixin { - // General metadata. - std::string detailed_name; - NtString hover; - NtString comments; + const char* detailed_name = ""; + const char* hover = ""; + const char* comments = ""; Maybe spell; Maybe extent; @@ -164,12 +155,6 @@ struct TypeDef : NameMixin { lsSymbolKind kind = lsSymbolKind::Unknown; std::vector GetBases() const { return bases; } - bool operator==(const TypeDef& o) const { - return detailed_name == o.detailed_name && spell == o.spell && - extent == o.extent && alias_of == o.alias_of && bases == o.bases && - types == o.types && funcs == o.funcs && vars == o.vars && - kind == o.kind && hover == o.hover && comments == o.comments; - } }; MAKE_REFLECT_STRUCT(TypeDef, detailed_name, @@ -199,9 +184,9 @@ struct IndexType { struct VarDef : NameMixin { // General metadata. - std::string detailed_name; - NtString hover; - NtString comments; + const char* detailed_name = ""; + const char* hover = ""; + const char* comments = ""; Maybe spell; Maybe extent; @@ -224,11 +209,6 @@ struct VarDef : NameMixin { } std::vector GetBases() const { return {}; } - bool operator==(const VarDef& o) const { - return detailed_name == o.detailed_name && spell == o.spell && - extent == o.extent && type == o.type && kind == o.kind && - storage == o.storage && hover == o.hover && comments == o.comments; - } }; MAKE_REFLECT_STRUCT(VarDef, detailed_name, diff --git a/src/messages/ccls_member_hierarchy.cc b/src/messages/ccls_member_hierarchy.cc index 9fa7cd6e..0f2132d8 100644 --- a/src/messages/ccls_member_hierarchy.cc +++ b/src/messages/ccls_member_hierarchy.cc @@ -94,9 +94,11 @@ void DoField(MessageHandler* m, } if (qualified) entry1.fieldName += def1->detailed_name; - else - entry1.fieldName += def1->detailed_name.substr(0, def1->qual_name_offset) + - std::string(def1->Name(false)); + else { + entry1.fieldName += + std::string_view(def1->detailed_name).substr(0, def1->qual_name_offset); + entry1.fieldName += def1->Name(false); + } if (def1->spell) { if (std::optional loc = GetLsLocation(m->db, m->working_files, *def1->spell)) diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 55d8a2e6..bed6295d 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -1,4 +1,3 @@ -#include "diagnostics_publisher.hh" #include "filesystem.hh" #include "include_complete.h" #include "log.hh" diff --git a/src/messages/text_document_hover.cc b/src/messages/text_document_hover.cc index 043953d3..36f5c710 100644 --- a/src/messages/text_document_hover.cc +++ b/src/messages/text_document_hover.cc @@ -11,7 +11,7 @@ std::optional GetComments(DB* db, SymbolRef sym) { std::optional ret; WithEntity(db, sym, [&](const auto& entity) { if (const auto* def = entity.AnyDef()) - if (!def->comments.empty()) { + if (def->comments[0]) { lsMarkedString m; m.value = def->comments; ret = m; @@ -29,10 +29,10 @@ std::optional GetHoverOrName(DB* db, if (const auto* def = entity.AnyDef()) { lsMarkedString m; m.language = LanguageIdentifier(lang); - if (!def->hover.empty()) { + if (def->hover[0]) { m.value = def->hover; ret = m; - } else if (!def->detailed_name.empty()) { + } else if (def->detailed_name[0]) { m.value = def->detailed_name; ret = m; } diff --git a/src/method.cc b/src/method.cc index 38da766a..722d6fb2 100644 --- a/src/method.cc +++ b/src/method.cc @@ -18,7 +18,7 @@ void Reflect(Reader& visitor, lsRequestId& value) { value.value = visitor.GetInt(); } else if (visitor.IsString()) { value.type = lsRequestId::kString; - value.value = atoll(visitor.GetString().c_str()); + value.value = atoll(visitor.GetString()); } else { value.type = lsRequestId::kNone; value.value = -1; diff --git a/src/nt_string.h b/src/nt_string.h deleted file mode 100644 index 0bc1e2c6..00000000 --- a/src/nt_string.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -// Nullable null-terminated string, which is null if default constructed, -// but non-null if assigned. -// This is used in Query{Func,Type,Var}::def to reduce memory footprint. -class NtString { - using size_type = std::string::size_type; - std::unique_ptr str; - - public: - NtString() = default; - NtString(NtString&& o) = default; - NtString(const NtString& o) { *this = o; } - NtString(std::string_view sv) { *this = sv; } - - const char* c_str() const { return str.get(); } - operator std::string_view() const { - if (c_str()) - return c_str(); - return {}; - } - bool empty() const { return !str || *c_str() == '\0'; } - - void operator=(std::string_view sv) { - str = std::unique_ptr(new char[sv.size() + 1]); - memcpy(str.get(), sv.data(), sv.size()); - str.get()[sv.size()] = '\0'; - } - void operator=(const NtString& o) { - *this = static_cast(o); - } - bool operator==(const NtString& o) const { - return str && o.str ? strcmp(c_str(), o.c_str()) == 0 - : c_str() == o.c_str(); - } -}; diff --git a/src/pipeline.cc b/src/pipeline.cc index aea96e26..13cef395 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -2,7 +2,6 @@ #include "clang_complete.h" #include "config.h" -#include "diagnostics_publisher.hh" #include "include_complete.h" #include "log.hh" #include "lsp.h" @@ -17,8 +16,42 @@ #include using namespace llvm; +#include #include +void DiagnosticsPublisher::Init() { + frequencyMs_ = g_config->diagnostics.frequencyMs; + match_ = std::make_unique(g_config->diagnostics.whitelist, + g_config->diagnostics.blacklist); +} + +void DiagnosticsPublisher::Publish(WorkingFiles* working_files, + std::string path, + std::vector diagnostics) { + // Cache diagnostics so we can show fixits. + working_files->DoActionOnFile(path, [&](WorkingFile* working_file) { + if (working_file) + working_file->diagnostics_ = diagnostics; + }); + + int64_t now = + std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()) + .count(); + if (frequencyMs_ >= 0 && (nextPublish_ <= now || diagnostics.empty()) && + match_->IsMatch(path)) { + nextPublish_ = now + frequencyMs_; + + Out_TextDocumentPublishDiagnostics out; + out.params.uri = lsDocumentUri::FromPath(path); + out.params.diagnostics = diagnostics; + ccls::pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out); + } +} + +namespace ccls::pipeline { +namespace { + struct Index_Request { std::string path; std::vector args; @@ -31,9 +64,6 @@ struct Stdout_Request { std::string content; }; -namespace ccls::pipeline { -namespace { - MultiQueueWaiter* main_waiter; MultiQueueWaiter* indexer_waiter; MultiQueueWaiter* stdout_waiter; @@ -115,8 +145,9 @@ std::unique_ptr RawCacheLoad( if (!file_content || !serialized_indexed_content) return nullptr; - return Deserialize(g_config->cacheFormat, path, *serialized_indexed_content, - *file_content, IndexFile::kMajorVersion); + return ccls::Deserialize(g_config->cacheFormat, path, + *serialized_indexed_content, *file_content, + IndexFile::kMajorVersion); } bool Indexer_Parse(DiagnosticsPublisher* diag_pub, diff --git a/src/pipeline.hh b/src/pipeline.hh index a3926594..d3c7dcf4 100644 --- a/src/pipeline.hh +++ b/src/pipeline.hh @@ -1,5 +1,6 @@ #pragma once +#include "lsp_diagnostic.h" #include "method.h" #include "query.h" @@ -7,12 +8,24 @@ #include #include -class DiagnosticsPublisher; +struct GroupMatch; struct VFS; struct Project; struct WorkingFiles; struct lsBaseOutMessage; +class DiagnosticsPublisher { + std::unique_ptr match_; + int64_t nextPublish_ = 0; + int frequencyMs_; + + public: + void Init(); + void Publish(WorkingFiles* working_files, + std::string path, + std::vector diagnostics); +}; + namespace ccls::pipeline { void Init(); diff --git a/src/query.cc b/src/query.cc index c4ef4129..dac2bc96 100644 --- a/src/query.cc +++ b/src/query.cc @@ -189,7 +189,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous, } for (auto& it : current->usr2func) { auto& func = it.second; - if (func.def.spell && func.def.detailed_name.size()) + if (func.def.spell && func.def.detailed_name[0]) r.funcs_def_update.emplace_back(it.first, func.def); r.funcs_declarations[func.usr].second = std::move(func.declarations); r.funcs_uses[func.usr].second = std::move(func.uses); @@ -208,7 +208,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous, }; for (auto& it : current->usr2type) { auto& type = it.second; - if (type.def.spell && type.def.detailed_name.size()) + if (type.def.spell && type.def.detailed_name[0]) r.types_def_update.emplace_back(it.first, type.def); r.types_declarations[type.usr].second = std::move(type.declarations); r.types_uses[type.usr].second = std::move(type.uses); @@ -226,7 +226,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous, } for (auto& it : current->usr2var) { auto& var = it.second; - if (var.def.spell && var.def.detailed_name.size()) + if (var.def.spell && var.def.detailed_name[0]) r.vars_def_update.emplace_back(it.first, var.def); r.vars_declarations[var.usr].second = std::move(var.declarations); r.vars_uses[var.usr].second = std::move(var.uses); @@ -353,7 +353,7 @@ int DB::Update(QueryFile::DefUpdate&& u) { void DB::Update(int file_id, std::vector>&& us) { for (auto& u : us) { auto& def = u.second; - assert(!def.detailed_name.empty()); + assert(def.detailed_name[0]); AssignFileId(file_id, def.spell); AssignFileId(file_id, def.extent); AssignFileId(file_id, def.callees); @@ -370,7 +370,7 @@ void DB::Update(int file_id, std::vector>&& us) { void DB::Update(int file_id, std::vector>&& us) { for (auto& u : us) { auto& def = u.second; - assert(!def.detailed_name.empty()); + assert(def.detailed_name[0]); AssignFileId(file_id, def.spell); AssignFileId(file_id, def.extent); auto R = type_usr.try_emplace({u.first}, type_usr.size()); @@ -387,7 +387,7 @@ void DB::Update(int file_id, std::vector>&& us) { void DB::Update(int file_id, std::vector>&& us) { for (auto& u : us) { auto& def = u.second; - assert(!def.detailed_name.empty()); + assert(def.detailed_name[0]); AssignFileId(file_id, def.spell); AssignFileId(file_id, def.extent); auto R = var_usr.try_emplace({u.first}, var_usr.size()); diff --git a/src/serializer.cc b/src/serializer.cc index 72090c6e..e29c1674 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -1,12 +1,15 @@ #include "serializer.h" #include "filesystem.hh" +#include "indexer.h" #include "log.hh" #include "serializers/binary.h" #include "serializers/json.h" -#include "indexer.h" +#include +#include +#include #include using namespace llvm; @@ -131,14 +134,12 @@ void Reflect(Writer& visitor, std::string_view& data) { visitor.String(&data[0], (rapidjson::SizeType)data.size()); } -void Reflect(Reader& visitor, NtString& value) { - if (!visitor.IsString()) - throw std::invalid_argument("std::string"); - value = visitor.GetString(); +void Reflect(Reader& vis, const char*& v) { + const char* str = vis.GetString(); + v = ccls::Intern(str); } -void Reflect(Writer& visitor, NtString& value) { - const char* s = value.c_str(); - visitor.String(s ? s : ""); +void Reflect(Writer& vis, const char*& v) { + vis.String(v); } void Reflect(Reader& visitor, JsonNull& value) { @@ -223,9 +224,9 @@ void ReflectHoverAndComments(Reader& visitor, Def& def) { template void ReflectHoverAndComments(Writer& visitor, Def& def) { // Don't emit empty hover and comments in JSON test mode. - if (!gTestOutputMode || !def.hover.empty()) + if (!gTestOutputMode || def.hover[0]) ReflectMember(visitor, "hover", def.hover); - if (!gTestOutputMode || !def.comments.empty()) + if (!gTestOutputMode || def.comments[0]) ReflectMember(visitor, "comments", def.comments); } @@ -234,7 +235,7 @@ void ReflectShortName(Reader& visitor, Def& def) { if (gTestOutputMode) { std::string short_name; ReflectMember(visitor, "short_name", short_name); - def.short_name_offset = def.detailed_name.find(short_name); + def.short_name_offset = std::string_view(def.detailed_name).find(short_name); assert(def.short_name_offset != std::string::npos); def.short_name_size = short_name.size(); } else { @@ -246,8 +247,8 @@ void ReflectShortName(Reader& visitor, Def& def) { template void ReflectShortName(Writer& visitor, Def& def) { if (gTestOutputMode) { - std::string short_name( - def.detailed_name.substr(def.short_name_offset, def.short_name_size)); + std::string_view short_name(def.detailed_name + def.short_name_offset, + def.short_name_size); ReflectMember(visitor, "short_name", short_name); } else { ReflectMember(visitor, "short_name_offset", def.short_name_offset); @@ -357,6 +358,21 @@ void Reflect(Writer& visitor, SerializeFormat& value) { } } +namespace ccls { +static BumpPtrAllocator Alloc; +static DenseSet Strings; +static std::mutex AllocMutex; + +const char* Intern(const std::string& str) { + if (str.empty()) return ""; + StringRef Str(str.data(), str.size() + 1); + std::lock_guard lock(AllocMutex); + auto R = Strings.insert(Str); + if (R.second) + *R.first = Str.copy(Alloc); + return R.first->data(); +} + std::string Serialize(SerializeFormat format, IndexFile& file) { switch (format) { case SerializeFormat::Binary: { @@ -451,3 +467,4 @@ std::unique_ptr Deserialize( file->path = path; return file; } +} diff --git a/src/serializer.h b/src/serializer.h index d2ee1191..1bbbc357 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -1,7 +1,6 @@ #pragma once #include "maybe.h" -#include "nt_string.h" #include @@ -42,7 +41,7 @@ class Reader { virtual int64_t GetInt64() = 0; virtual uint64_t GetUInt64() = 0; virtual double GetDouble() = 0; - virtual std::string GetString() = 0; + virtual const char* GetString() = 0; virtual bool HasMember(const char* x) = 0; virtual std::unique_ptr operator[](const char* x) = 0; @@ -180,8 +179,8 @@ void Reflect(Writer& visitor, std::string& value); void Reflect(Reader& visitor, std::string_view& view); void Reflect(Writer& visitor, std::string_view& view); -void Reflect(Reader& visitor, NtString& value); -void Reflect(Writer& visitor, NtString& value); +void Reflect(Reader& vis, const char*& v); +void Reflect(Writer& vis, const char*& v); void Reflect(Reader& visitor, JsonNull& value); void Reflect(Writer& visitor, JsonNull& value); @@ -322,6 +321,8 @@ void ReflectMember(Writer& vis, const char* name, T& v) { // API +namespace ccls { +const char* Intern(const std::string& str); std::string Serialize(SerializeFormat format, IndexFile& file); std::unique_ptr Deserialize( SerializeFormat format, @@ -329,3 +330,4 @@ std::unique_ptr Deserialize( const std::string& serialized_index_content, const std::string& file_content, std::optional expected_version); +} diff --git a/src/serializers/binary.h b/src/serializers/binary.h index 821c4367..7327ba15 100644 --- a/src/serializers/binary.h +++ b/src/serializers/binary.h @@ -52,13 +52,12 @@ class BinaryReader : public Reader { uint32_t GetUInt32() override { return VarUInt(); } uint64_t GetUInt64() override { return VarUInt(); } double GetDouble() override { return Get(); } - std::string GetString() override { - if (auto n = VarUInt()) { - std::string ret(p_, n); - p_ += n; - return ret; - } - return ""; + const char* GetString() override { + const char* ret = p_; + while (*p_) + p_++; + p_++; + return ret; } bool HasMember(const char* x) override { return true; } @@ -118,9 +117,8 @@ class BinaryWriter : public Writer { void Double(double x) override { Pack(x); } void String(const char* x) override { String(x, strlen(x)); } void String(const char* x, size_t len) override { - VarUInt(len); auto i = buf_.size(); - buf_.resize(i + len); + buf_.resize(i + len + 1); memcpy(buf_.data() + i, x, len); } void StartArray(size_t n) override { VarUInt(n); } diff --git a/src/serializers/json.h b/src/serializers/json.h index b5c84c04..b650f83b 100644 --- a/src/serializers/json.h +++ b/src/serializers/json.h @@ -29,7 +29,7 @@ class JsonReader : public Reader { uint32_t GetUInt32() override { return uint32_t(m_->GetUint64()); } uint64_t GetUInt64() override { return m_->GetUint64(); } double GetDouble() override { return m_->GetDouble(); } - std::string GetString() override { return m_->GetString(); } + const char* GetString() override { return m_->GetString(); } bool HasMember(const char* x) override { return m_->HasMember(x); } std::unique_ptr operator[](const char* x) override { diff --git a/src/test.cc b/src/test.cc index c9dff5cf..4ba66071 100644 --- a/src/test.cc +++ b/src/test.cc @@ -191,10 +191,10 @@ void DiffDocuments(std::string path, void VerifySerializeToFrom(IndexFile* file) { std::string expected = file->ToString(); - std::string serialized = Serialize(SerializeFormat::Json, *file); + std::string serialized = ccls::Serialize(SerializeFormat::Json, *file); std::unique_ptr result = - Deserialize(SerializeFormat::Json, "--.cc", serialized, "", - std::nullopt /*expected_version*/); + ccls::Deserialize(SerializeFormat::Json, "--.cc", serialized, "", + std::nullopt /*expected_version*/); std::string actual = result->ToString(); if (expected != actual) { fprintf(stderr, "Serialization failure\n");