Internalize strings & remove diagnostics_publisher.cc

This commit is contained in:
Fangrui Song 2018-06-07 21:53:41 -07:00
parent c8a81aeae3
commit e5d8153d4b
20 changed files with 170 additions and 217 deletions

View File

@ -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

View File

@ -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<std::string_view>(ret);
return ret;
}
std::string ClangCursor::ToString() const {

View File

@ -1,5 +1,4 @@
#pragma once
#include "nt_string.h"
#include "position.h"
#include <clang-c/Index.h>
@ -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;

View File

@ -1,36 +0,0 @@
#include "diagnostics_publisher.hh"
#include "pipeline.hh"
using namespace ccls;
#include <chrono>
void DiagnosticsPublisher::Init() {
frequencyMs_ = g_config->diagnostics.frequencyMs;
match_ = std::make_unique<GroupMatch>(g_config->diagnostics.whitelist,
g_config->diagnostics.blacklist);
}
void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
std::string path,
std::vector<lsDiagnostic> 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::milliseconds>(
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);
}
}

View File

@ -1,16 +0,0 @@
#include "lsp_diagnostic.h"
#include "match.h"
#include "working_files.h"
class DiagnosticsPublisher {
std::unique_ptr<GroupMatch> match_;
int64_t nextPublish_ = 0;
int frequencyMs_;
public:
void Init();
void Publish(WorkingFiles* working_files,
std::string path,
std::vector<lsDiagnostic> diagnostics);
};

View File

@ -3,6 +3,7 @@
#include "log.hh"
#include "platform.h"
#include "serializer.h"
using ccls::Intern;
#include <clang/AST/AST.h>
#include <clang/Frontend/ASTUnit.h>
@ -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<int> 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<Usr>& 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<class T> 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 T> class function; // not visited by
// OnIndexDeclaration template<> class function<int> {}; // 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) {

View File

@ -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 <typename D>
struct NameMixin {
std::string_view Name(bool qualified) const {
auto self = static_cast<const D*>(this);
return qualified ? std::string_view(
self->detailed_name.c_str() + self->qual_name_offset,
self->short_name_offset - self->qual_name_offset +
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.c_str() +
self->short_name_offset,
: std::string_view(self->detailed_name + self->short_name_offset,
self->short_name_size);
}
};
struct FuncDef : NameMixin<FuncDef> {
// General metadata.
std::string detailed_name;
NtString hover;
NtString comments;
const char* detailed_name = "";
const char* hover = "";
const char* comments = "";
Maybe<Use> spell;
Maybe<Use> extent;
@ -105,13 +104,6 @@ struct FuncDef : NameMixin<FuncDef> {
clang::StorageClass storage = clang::SC_None;
std::vector<Usr> 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<IndexFunc> {
};
struct TypeDef : NameMixin<TypeDef> {
// General metadata.
std::string detailed_name;
NtString hover;
NtString comments;
const char* detailed_name = "";
const char* hover = "";
const char* comments = "";
Maybe<Use> spell;
Maybe<Use> extent;
@ -164,12 +155,6 @@ struct TypeDef : NameMixin<TypeDef> {
lsSymbolKind kind = lsSymbolKind::Unknown;
std::vector<Usr> 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<VarDef> {
// General metadata.
std::string detailed_name;
NtString hover;
NtString comments;
const char* detailed_name = "";
const char* hover = "";
const char* comments = "";
Maybe<Use> spell;
Maybe<Use> extent;
@ -224,11 +209,6 @@ struct VarDef : NameMixin<VarDef> {
}
std::vector<Usr> 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,

View File

@ -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<lsLocation> loc =
GetLsLocation(m->db, m->working_files, *def1->spell))

View File

@ -1,4 +1,3 @@
#include "diagnostics_publisher.hh"
#include "filesystem.hh"
#include "include_complete.h"
#include "log.hh"

View File

@ -11,7 +11,7 @@ std::optional<lsMarkedString> GetComments(DB* db, SymbolRef sym) {
std::optional<lsMarkedString> 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<lsMarkedString> 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;
}

View File

@ -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;

View File

@ -1,42 +0,0 @@
#pragma once
#include <string.h>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
// 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<char[]> 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<char[]>(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<std::string_view>(o);
}
bool operator==(const NtString& o) const {
return str && o.str ? strcmp(c_str(), o.c_str()) == 0
: c_str() == o.c_str();
}
};

View File

@ -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 <llvm/Support/Timer.h>
using namespace llvm;
#include <chrono>
#include <thread>
void DiagnosticsPublisher::Init() {
frequencyMs_ = g_config->diagnostics.frequencyMs;
match_ = std::make_unique<GroupMatch>(g_config->diagnostics.whitelist,
g_config->diagnostics.blacklist);
}
void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
std::string path,
std::vector<lsDiagnostic> 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::milliseconds>(
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<std::string> 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<IndexFile> 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,

View File

@ -1,5 +1,6 @@
#pragma once
#include "lsp_diagnostic.h"
#include "method.h"
#include "query.h"
@ -7,12 +8,24 @@
#include <unordered_map>
#include <vector>
class DiagnosticsPublisher;
struct GroupMatch;
struct VFS;
struct Project;
struct WorkingFiles;
struct lsBaseOutMessage;
class DiagnosticsPublisher {
std::unique_ptr<GroupMatch> match_;
int64_t nextPublish_ = 0;
int frequencyMs_;
public:
void Init();
void Publish(WorkingFiles* working_files,
std::string path,
std::vector<lsDiagnostic> diagnostics);
};
namespace ccls::pipeline {
void Init();

View File

@ -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<std::pair<Usr, QueryFunc::Def>>&& 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<std::pair<Usr, QueryFunc::Def>>&& us) {
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& 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<std::pair<Usr, QueryType::Def>>&& us) {
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryVar::Def>>&& 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());

View File

@ -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 <llvm/ADT/CachedHashString.h>
#include <llvm/ADT/DenseSet.h>
#include <mutex>
#include <stdexcept>
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 <typename Def>
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 <typename Def>
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<StringRef> 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<IndexFile> Deserialize(
file->path = path;
return file;
}
}

View File

@ -1,7 +1,6 @@
#pragma once
#include "maybe.h"
#include "nt_string.h"
#include <llvm/Support/Compiler.h>
@ -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<Reader> 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<IndexFile> Deserialize(
SerializeFormat format,
@ -329,3 +330,4 @@ std::unique_ptr<IndexFile> Deserialize(
const std::string& serialized_index_content,
const std::string& file_content,
std::optional<int> expected_version);
}

View File

@ -52,14 +52,13 @@ class BinaryReader : public Reader {
uint32_t GetUInt32() override { return VarUInt(); }
uint64_t GetUInt64() override { return VarUInt(); }
double GetDouble() override { return Get<double>(); }
std::string GetString() override {
if (auto n = VarUInt()) {
std::string ret(p_, n);
p_ += n;
const char* GetString() override {
const char* ret = p_;
while (*p_)
p_++;
p_++;
return ret;
}
return "";
}
bool HasMember(const char* x) override { return true; }
std::unique_ptr<Reader> operator[](const char* x) override { return {}; }
@ -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); }

View File

@ -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<Reader> operator[](const char* x) override {

View File

@ -191,9 +191,9 @@ 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<IndexFile> result =
Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
ccls::Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
std::nullopt /*expected_version*/);
std::string actual = result->ToString();
if (expected != actual) {